LINUX.ORG.RU

[C++] Массив разных классов и массив ссылок на разные классы

 


0

0

Есть класс Rectangle (прямоугольник). У него есть размеры по x и y и координаты центра.

Наследованием созданы классы ColoredRectangle (цветной прямоугольник) и PatternedRectangle (прямоугольник с текстурой). У обоих есть функции Draw(), рисующие их.

Надо сделать массив (желательно, vector) rectangleMass, содержащий как цветные, так и текстурированные прямоугольники, чтобы потом пройтись по нему, вызывая для каждого элемента Draw. Также нужен массив (опять же, желательно vector), содержащий указатели на некоторые элементы из rectangleMass.

Это возможно?

★★★★★

Последнее исправление: Obey-Kun (всего исправлений: 1)

то ли дело на питоне

dimon555 ★★★★★
()
Ответ на: комментарий от zJes

я так понимаю, мне нужны виртуальные методы и абстрактные классы...

создаётся абстрактный класс Rectangle, от него наследуются ColoredRectangle и PatternedRectangle. Создаём vector<Rectangle> rectangleVector и можем с ним работать как хочется, верно? Или как? Как будет использоваться этот вектор?

А если у ColoredRectangle есть функция SetColor() (которая отсутствует у PatternedRectangle), я могу сказать rectangleVector.SetColor(...), если i-й элемент заведомо является ColoredRectangle'ом?

или я всё неправильно понял?

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

Самый дебильный вариант:
[code=cpp]
class Rectangle
{
public:
virtual void Draw() = 0;
virtual void SetColor(){}
};

class ColoredRectangle: public Rectangle
{
public:
virtual void Draw(){
....
}
virtual void SetColor(){
....
}
}

class PatternedRectangle : public Rectangle
{
public:
virtual void Draw(){
...
}
};

std::vector<Rectangle*> vect;
vect.push_back(new ColoredRectangle());
vect.push_back(new PatternedRectangle());

[/code]Не очень красиво, зато безопасно :)

zJes ★★
()
Ответ на: комментарий от zJes

> Я и написал, дебильный вариант...

ну и зачем давать новичку «дебильный вариант»? чтоб он начал повторять?

lester ★★★★
()
Ответ на: комментарий от zJes

> Напиши доходчиво, правильно, что бы было просто для понимания?

если человек не знает про виртульные методы, абстрактные методы и классы, dynamic_cast и QI и т.д. и т.п., то смысл ему показывать на пальцах решение и разжевывать что к чему? это ведь не что-то сверхъестестенное - открыть хотя бы того же Страуструпа и прочитать

lester ★★★★
()
Ответ на: комментарий от lester

> если человек не знает про виртульные методы, абстрактные методы и классы,

я уже всё понял, просто сначала под пивом кусок Шилдта не осилил

dynamic_cast

это я тоже знаю, хочу обойтись без cast

можешь показаться не дебильный вариант (без разжёвывания), я с утра разберусь?

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

> можешь показаться не дебильный вариант (без разжёвывания), я с утра разберусь?

то есть показать...

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

ещё можно отослать на нужную часть литературу

в идеале — показаться пример и отослать на литературу

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

> нужную часть литературу

литературЫ

всё, надо спать, башка и так 6й час как не варит

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

> можешь показаться не дебильный вариант

создаешь интерфейс I_Rectangle, потом его базовую реализацию - Rectangle, потом дочерние классы ColoredRectangle и PatternedRectangle , и набиваешь в вектор std::vector<I_Rectangle*> создаваемые объекты

если i-й элемент заведомо является ColoredRectangle'ом


делаешь dynamic_cast, проверяешь на NULL и вызываешь метод, хотя опять же - по хорошему код, знающий, что данный объект именно ColoredRectangle, должен быть в самом ColoredRectangle, либо дочерних классах от него ( как простой вариант - это вызов диалога смены цвета, например, и тогда нужен еще один интерфейс, чтоб получить контекстное меню или тот же диалог свойств, ну то уже я увлекся )

Также нужен массив (опять же, желательно vector), содержащий указатели на некоторые элементы из rectangleMass.


указатели на элементы вектора делать нельзя( т.е. можно - но будешь ССЗБ )

lester ★★★★
()
Ответ на: комментарий от Obey-Kun

> ещё можно отослать на нужную часть литературу

на нужную не укажу - так как читать выборочно нет смысла, а из популярных( даже попсовых ) - Мартин Фаулер, Александреску, Страуструп, Джоэль, Мейерс, Макконнелл и т.д.

lester ★★★★
()
Ответ на: комментарий от lester

> указатели на элементы вектора делать нельзя( т.е. можно - но будешь ССЗБ )

я не собираюсь делать с этим вектором ничего, кроме дописывания элементов в конец... т.е. никаких смещений, удалений и т.д., только дописывание в конец. Соответственно, вполне можно использовать указатели на его элементы, если я всё правильно понимаю.

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

> я не собираюсь делать с этим вектором ничего, кроме дописывания элементов в конец... т.е. никаких смещений, удалений и т.д., только дописывание в конец. Соответственно, вполне можно использовать указатели на его элементы, если я всё правильно понимаю.

во-первых «дописывания элементов в конец» - вполне достаточно, чтоб словить крэш( почему - сам должен догадаться ), а во-вторых это ты сейчас не собираешься менять исходный вектор, а потом понадобится - и ты без тени смущения это сделаешь, т.к. забудешь про эту завязку, и веселые, почти рандомные глюки, будут обеспечены

lester ★★★★
()
Ответ на: комментарий от lester

> а во-вторых это ты сейчас не собираешься менять исходный вектор, а потом понадобится - и ты без тени смущения это сделаешь, т.к. забудешь про эту завязку, и веселые, почти рандомные глюки, будут обеспечены

тут просто матмодель такая, что не придётся менять исходный вектор...

там вообще довольно хитрая штука... у нас есть много прямоугольников, которые образуют узор (на самом деле разбивают поле на ячейки, но не суть). Для каждого прямоугольника нужен массив указателей на все соседние прямоугольники (т.е. те, с которыми он соприкасается). заполняться оно будет так:

1. создать массив прямоугольников

<после этого он больше не изменяется!>

2. для каждого прямоугольника заполнить массив соседей указателями на соответствующих соседей

3. матан-матан-матан

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

> для каждого прямоугольника заполнить массив соседей указателями на соответствующих соседей

а зачем тут делать указатель на элемент вектора? копируешь указатель на сам объект и все

lester ★★★★
()
Ответ на: комментарий от lester

в общем, для реализации того, что мне нужно, следует заботать абстрактные классы и интерфейсы, так?

ещё небольшое пояснение... у меня есть два типа прямоугольников... прямоугольники первого типа влияют на соседей, но сами никогда не меняются... прямоугольники второго типа влияют на соседей, а соседи влияют на них. Для прямоугольников второго типа есть понятие внутренней энергии, она-то и меняется; для первого типа прямоугольников этого понятия нет. Поэтому я и спрашивал про SetColor(), существующий только для одного типа.

тут хватит интерфейсов и классов, или таки нужно использовать dynamic_cast?

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от lester

можешь показать разницу между указателем на элемент вектора и на сам объект?

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от lester

большое спасибо за помощь нубу вроде меня... пойду пока что спать, ещё на пары идти...

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

> тут хватит интерфейсов и классов, или таки нужно использовать dynamic_cast?

dynamic_cast это медленная операция и как я уже говорил - нежелательная, вообще тут, даже для такой простой задачи, есть несколько вариантов реализации, все зависит от необходимой расширяемости и требуемой скорости работы

lester ★★★★
()
Ответ на: комментарий от anonymous

то что в один класс намешали все, что захотели - и абстрактные методы, и метод SetColor, который собственно к Rectangle никаким боком не относится - т.е. костыль, и судя по условию тут еще и собсвенно реализация базового класса - выставление позиции и размеров, вобщем каша, а не код

lester ★★★★
()
Ответ на: комментарий от lester
class ColoredRectangle;
class PatternedRectangle;
class Rectangle {
public:
    virtual void Draw() = 0;

    virtual ColoredRectangle* asColoredRectangle() { return 0; }
    virtual PatternedRectangle* asPatternedRectangle() { return 0; }
};

class ColoredRectangle: public Rectangle {
public:
    virtual void Draw() {
        // ...
    }
    virtual void SetColor() {
        // ...
    }

    virtual ColoredRectangle* asColoredRectangle() { return this; }
}

class PatternedRectangle : public Rectangle {
public:
    virtual void Draw(){
        // ...
    }

    virtual PatternedRectangle* asPatternedRectangle() { return this; }
};

Такой вариант тоже является быдлокодом и костылем для замены dynamic_cast'а?

anonymous
()

Используйте разные массивы для разных интерфесов. А эти массивы положите в другой массив.

Booster ★★
()
Ответ на: комментарий от anonymous

> Такой вариант тоже является быдлокодом и костылем для замены dynamic_cast'а?

да - Rectangle не должен ничего знать про своих потомков, для такого рода «кастинга» есть QI

lester ★★★★
()
Ответ на: комментарий от lester

Что такое QI? Гугл, кроме языка программирования Qi, ничего не подсказывает?

// совершенно другой анонимус

anonymous
()
Ответ на: комментарий от lester

Т.е. в Qt быдлокод? QDomNode умеет:

QDomAttr toAttr () const
QDomCDATASection toCDATASection () const
QDomCharacterData toCharacterData () const
QDomComment toComment () const
QDomDocument toDocument () const
...
которые являются его наследниками.

// все тот-же, совершенно другой, анонимус

anonymous
()
Ответ на: комментарий от anonymous

>Что такое QI? Гугл, кроме языка программирования Qi, ничего не подсказывает?
То же самый набор массивов, про который я писал, но только с методом возвращающим нужный массив/сущность.

Booster ★★
()
Ответ на: комментарий от anonymous

Я полагаю, что он имел ввиду то, что такой код неуместен в данном случае.

Тем не менее, мне тоже интересно знать, что же такое QI? Похоже, что-то очень популярное, раз lester не удосужился заранее предоставить линк или какое-нибудь минимальное объяснение.

// тот самый первый анонимус

anonymous
()
Ответ на: комментарий от anonymous

> Т.е. в Qt быдлокод? QDomNode умеет:

оттуда же:

// Dynamic cast
virtual bool isAttr() const { return false; }
virtual bool isCDATASection() const { return false; }
virtual bool isDocumentFragment() const { return false; }
virtual bool isDocument() const { return false; }
virtual bool isDocumentType() const { return false; }
virtual bool isElement() const { return false; }
virtual bool isEntityReference() const { return false; }
virtual bool isText() const { return false; }
virtual bool isEntity() const { return false; }
virtual bool isNotation() const { return false; }
virtual bool isProcessingInstruction() const { return false; }
virtual bool isCharacterData() const { return false; }
virtual bool isComment() const { return false; }

это нормальный код?

lester ★★★★
()
Ответ на: комментарий от lester

это нормальный код?

т.е. лучше каждый раз делать dynamic_cast и сравнивать с нулем, чтобы узнать, это искомый тип или нет?

anonymous
()
Ответ на: комментарий от anonymous

> т.е. лучше каждый раз делать dynamic_cast и сравнивать с нулем, чтобы узнать, это искомый тип или нет?

нет конечно - лучше брать тип и сравнивать

lester ★★★★
()
Ответ на: комментарий от anonymous

ну и в данном случае это приватный код - т.е. не для удобства пользователя, а чтоб обойтись без dynamic_cast - очевидно из соображений эффективности

lester ★★★★
()
Ответ на: комментарий от Gorthauer

> И все блин дружно забыли про виртуальные деструкторы. Мемори ликов захотелось?

тоже верно - не обратил внимания на этот недочет

lester ★★★★
()

Ещё заслуживает внимания идея группировки интерфейсов. Грубо говоря есть массив массивов объектов и при запросе конкретного интерфейса, возвращается указатель на первый массив + диапазон(кол-во массивов). Таким образом мы получаем все объекты данного интерфейса, несмотря на то что могут попадаться и производные запрошенному интерфейсу классы.

Booster ★★
()
Ответ на: комментарий от lester

>это нормальный код?

А есть способ сделать, чтобы это работало быстрее?


Редиректю запрос.

Booster ★★
()
Ответ на: комментарий от lester

Ахтунг!!! lester хочет поиметь мозг несчастного эээ... St_MPA3b-и. Ну и мути развели. Боюсь скоро надо будет лечить «пациента» от ЪГМ (Ъ головного мозга)

pathfinder ★★★★
()
Ответ на: комментарий от anonymous

А что здесь быдлокодерского?

class Rectangle 
{ 
public: 
virtual void Draw() = 0; 
virtual void SetColor(){} 
};

ИМХО былокод имеет место быть.

1. SetColor() в базовом классе как я понял не нужен.

2. virtual void SetColor(){}. Объявление отдельно, реализация отдельно.

3. Если класс будет наследуемый то стоит стразу в базовом классе сделать виртуальный деструктор. Иначе словите много «радости»

Предлагаю свой вариант (для обсирания)

class Rectangle
{
public:
  double x; //Координаты центра
  double y; 
  double sx; //Размеры прямоугольника
  double sy;
  virtual ~Rectangle(); //ИМНО нужен
  virtual void Draw(); //метод рисования, можно абстрактный
};

//В векторе храним исключительно УКАЗАТЕЛИ а не сам класс
//ИМХО писать что-то вроде vector<Rectangle> надо с большой осторожностью
vector<Rectangle*> recv_arr; 

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

В векторе храним указатели всех экземпляров наследников от Rectangle. Если надо, то можно завести ещё несколько векторов с указателями некоторые экземпляры. ИМХО всегда лучше иметь что-то вроде «главного хранилища» и жизненный цикл объектов привязывать к жизненному циклу соответствующих указателей в этом хранилище. Это может помочь в контроле за жизненным циклом объектов.

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

>2. virtual void SetColor(){}. Объявление отдельно, реализация отдельно.

Бред читой воды.

Но в целом согласен, я бы тоже не стал городить лишнийх интерфейсов по чем зря.

staseg ★★★★★
()
Ответ на: комментарий от Gorthauer

А есть способ сделать, чтобы это работало быстрее?

конечно, у них это потом еще раз обернуто:

bool QDomNode::isCDATASection() const
{
if(impl)
return impl->isCDATASection();
return false;
}

и обычный node.mType == kCDATASection будет однозначно в разы быстрее вызова виртуального метода node->isCDATASection()

lester ★★★★
()
Ответ на: комментарий от lester

не считая того, что их конструкции навроде «p->isText() || p->isCDATASection() || ...» превратятся в обычный switch, который опять же будет быстрей

lester ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.