Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.236.100.210] |
|
Сообщ.
#1
,
|
|
|
Есть несколько классов, которые наследуются от CDialogEx.
class CGreenDialog : public CDialogEx { public: void Calculate(); } class CRedDialog : public CDialogEx { public: void Calculate(); } В этих классах нужно добавить некий метод (например Calculate()), который потом будет должен вызываться обобщенно. Например: CDialogEx* dlg[10]; dlg[0] = new CGreenDialog(); dlg[1] = new CRedDialog(); //... for (i=0; i<10; i++) dlg[i]->Calculate(); //Так нельзя, т.к. в CDialogEx нет такого метода. Можно преобразовать так: ((CRedDialog*)dlg[i])->Calculate(); Но в dlg может быть класс другого типа. Подскажите пожалуйста, как это правильно реализовать? |
Сообщ.
#2
,
|
|
|
Простой вариант: добавляешь виртуальный метод Calculate() в CDialogEx и перекрываешь в каждом производном. Вызываешь через CDialogEx по ссылке или указателю, в run-time всё разрулится само.
Есть более гибкий, но сложнее. Нужен? Добавлено Ладно, будем считать, что нужен. Создаёшь "интерфейс" в лице абстрактного класса, например, ICalculate. В нём объявляешь нужный тебе виртуальный метод Calculate(). struct ICalculate { virtual void Calculate() = 0; }; class CGreenDialog: public CDialogEx, public ICalculate { public: void Calculate(); }; class CRedDialog : public CDialogEx, public ICalculate { public: void Calculate(); }; CDialogEx* dlg[10]; dlg[0] = new CGreenDialog(); dlg[1] = new CRedDialog(); //... for (i=0; i<10; i++) { ICalculate* iptr = dynamic_cast<ICalculate*>(dlg[i]); if (iptr != NULL) iptr->Calculate(); } |
Сообщ.
#3
,
|
|
|
Да, сложность заключалась именно в том, что нельзя вмешиваться в CDialogEx.
Второй пример (дополнение) работает как надо! Большое спасибо! p.s. Так примерно и делал (с множественным наследованием), но использовал не struct, а class. И преобразование делал так (видимо неправильно): //неправильный код ICalculate* iptr = (ICalculate*)(dlg[i]); if (iptr != NULL) iptr->Calculate(); Поэтому программа вылетала с ошибкой. |
Сообщ.
#4
,
|
|
|
Цитата ViH @ Без разницы. Интерфейсы обычно содержат только публичные методы, т.к. описывают возможные воздействия на объект, реализующий этот интерфейс, поэтому struct просто позволяет экономить на неуказании public.Так примерно и делал (с множественным наследованием), но использовал не struct, а class. Цитата ViH @ Да. Компилятор не видит способа преобразовать CDialogEx в ICalculate, т.к. между ними нет ни никакого родства, ни кастующих конструкторов или операторов. Поэтому применяет семантику reinterpret_cast<>, что неправильно. Тут нужна семантика static_cast, но для этого нужно как-то объяснить компилятору маршрут по иерархии, а значит через промежуточный общий узел. В твоём случае это один из производных классов, для которого и CDialogEx, и ICalculate являются базовыми, т.е. два каста: сначала в производный, потом в другой базовый. Но тут ты столкнёшься с той же самой проблемой: dlg может не быть ни одним из производных от CDialogEx. dynamic_cast<> имеет семантику как раз static_cast<>, но проверяет иерархию в run-time, поэтому идеально подходит. Он даже лучше, т.к. не требует промежуточных узлов. Опять же, если проводить аналогию с COM, то dynamic_cast<> — это аналог QueryInterface() И преобразование делал так (видимо неправильно): ... Поэтому программа вылетала с ошибкой. Добавлено Да, и ещё пару советов на всякий случай. |
Сообщ.
#5
,
|
|
|
Спасибо большое за объяснение внутренней работы. Очень полезно!
|
Сообщ.
#6
,
|
|
|
Цитата Qraizer @ Если знаком с COM, этот метод не должен шокировать. Это из S.O.L.I.D, четвертый принцип - "Разделение интерфейсов" Ответил просто так, как-то топик попался на глаза и увидел знакомое |