Есть два типа портов — PortA и PortB. У них есть как одинаковые методы, так и специфичные. Наружу модуля должны торчать только интерфейсы: IPortA и IPortB. Хочется реализовать это красиво с минимальным повторением кода.
//! Общий интерфейс для всех портовclass IPort
{
virtual void func() = 0;
};
//! Специфичный интерфейс порта Аclass IPortA : public IPort
{
virtual void funcA() = 0;
};
//! Специфичный интерфейс порта Бclass IPortB : public IPort
{
virtual void funcB() = 0;
};
class Port : public IPort
{
void func();
};
class PortA: public Port, public IPortA
{
void funcA();
};
class PortB: public Port, public IPortB
{
void funcB();
};
Компилятор (VC) выдает:
file.cpp(174) : error C2259: 'PortA' : cannot instantiate abstract class
due to following members:
'void IPort::func(void)' : pure virtual function was not defined
A>
A>class PortA: public Port, public IPortA
A>{
A> void funcA();
virtual void func() { return Port::func(); }
A>};
A>class PortB: public Port, public IPortB
A>{
A> void funcB();
virtual void func() { return Port::func(); }
A>};
A>
Это вам не c#, тут Port::func на IPort::func мапиться не будет
Здравствуйте, agaf, Вы писали:
A>Есть два типа портов — PortA и PortB. У них есть как одинаковые методы, так и специфичные. Наружу модуля должны торчать только интерфейсы: IPortA и IPortB. Хочется реализовать это красиво с минимальным повторением кода.
Буквально на прошлой неделе сам с этим боролся...
читать <a href="http://www.rsdn.ru/forum/message/2541889.aspx
A>//! Общий интерфейс для всех портов
A>class IPort
A>{
A> virtual void func() = 0;
A>};
A>//! Специфичный интерфейс порта А
A>class IPortA : publicvirtual IPort
A>{
A> virtual void funcA() = 0;
A>};
A>//! Специфичный интерфейс порта Б
A>class IPortB : publicvirtual IPort
A>{
A> virtual void funcB() = 0;
A>};
A>class Port : publicvirtual IPort
A>{
A> void func();
A>};
A>class PortA: public Port, public IPortA
A>{
A> void funcA();
A>};
A>class PortB: public Port, public IPortB
A>{
A> void funcB();
A>};
A>
Здравствуйте, NikeByNike, Вы писали:
NBN>Здравствуйте, _Paul, Вы писали:
_P>>Здравствуйте, agaf, Вы писали:
_P>>Тебе поможет виртуальное наследование:
NBN>Имхо здесь явно проблемы в архитектуре. К сожалению не готов предложить лучшую...
//! Общий интерфейс для всех портовstruct IPort
{
virtual void func() = 0;
};
//! Специфичный интерфейс порта Аstruct IPortA
{
virtual void funcA() = 0;
virtual IPort* GetIPort() = 0;
};
//! Специфичный интерфейс порта Бstruct IPortB
{
virtual void funcB() = 0;
virtual IPort* GetIPort() = 0;
};
class Port : public IPort
{
void func();
};
class PortA: public Port, public IPortA
{
void funcA();
IPort* GetIPort() { return this; }
};
class PortB: public Port, public IPortB
{
void funcB();
IPort* GetIPort() { return this; }
};
Ну а от IPort к IPortA переходил бы по dynamic_cast...
А виртуальных баз вообще бы не клал...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, _Paul, Вы писали:
_P>>>Тебе поможет виртуальное наследование:
NBN>>Имхо здесь явно проблемы в архитектуре. К сожалению не готов предложить лучшую...
_P>Паттерн Bridge?
Не знаю я не вполне уверен, что правильно понимаю задачу. Возможно лучше было бы решить так:
// interfaceclass IPort
{
virtual void PortFunc() = 0;
};
class IPortA : public IPort
{
virtual void PortFuncA() = 0;
};
class IPortB : public IPort
{
virtual void PortFuncB() = 0;
};
// implementationtemplate<class TInterface>
class Port
{
void PortFunc() {}
};
template<class TInterface>
class PortA : public Port<TInterface>
{
void PortFuncA() {}
};
template<class TInterface>
class PortB : public Port<TInterface>
{
void PortFuncB() {}
};
IPortA* CreatePortA() { return new PortA<IPortA>; }
IPortB* CreatePortB() { return new PortB<IPortB>; }
_Paul! А что не так?
Не говоря уже о том, что не соглашаться с сообщением "я бы сделал так" нелогично
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
NBN>IPortA* CreatePortA() { return new PortA<IPortA>; }
NBN>IPortB* CreatePortB() { return new PortB<IPortB>; }
Приём занятный, но, в случае множественной реализации интерфейсов будет очень громоздко
Всё-таки мне больше нравится в такой последовательности:
1) Вообще отказаться от наследования интерфейсов. (Проблем никаких, всё понятно, предсказуемо, без накладных расходов, да и совместимо с любыми языками)
2) Виртуально выводиться из базовых интерфейсов
3) Схемы с шаблонами
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, agaf, Вы писали:
A>Есть два типа портов — PortA и PortB. У них есть как одинаковые методы, так и специфичные. Наружу модуля должны торчать только интерфейсы: IPortA и IPortB. Хочется реализовать это красиво с минимальным повторением кода.
A>
A>//! Общий интерфейс для всех портов
A>class IPort
A>{
A> virtual void func() = 0;
A>};
A>//! Специфичный интерфейс порта А
A>class IPortA : public IPort
A>{
A> virtual void funcA() = 0;
A>};
A>//! Специфичный интерфейс порта Б
A>class IPortB : public IPort
A>{
A> virtual void funcB() = 0;
A>};
A>class Port : public IPort
A>{
A> void func();
A>};
A>class PortA: public Port, public IPortA
A>{
A> void funcA();
A>};
A>class PortB: public Port, public IPortB
A>{
A> void funcB();
A>};
A>
Поскольку "Наружу модуля должны торчать только интерфейсы: IPortA и IPortB", то может IPort вообще не нужен? Ну сделайте базовую реализацию с func() и всё, зачем её в отдельный интерфей выносить?
Здравствуйте, Erop, Вы писали:
E>1) Вообще отказаться от наследования интерфейсов. (Проблем никаких, всё понятно, предсказуемо, без накладных расходов, да и совместимо с любыми языками)
А что предложить в замен?
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Может, сделаешь интерфейсы COM-совместимыми, и заюзаешь ATL?
В форуме по ATL можно поискать — там рассказывался способ как делать реализации унаследованных друг от друга интерфейсов. В принципе, то же самое можно и без ATL — на случай если приложение невиндовое.
Здравствуйте, Erop, Вы писали:
E>Приём занятный, но, в случае множественной реализации интерфейсов будет очень громоздко
Ye я в принципе не первый раз такую схему применяю. Подозреваю, что система работы с портами достаточно компактна, так что такая схема будет работать прекрасно...
Кстати забыл написать:
template<class TInterface>
class Port : public TInterface
{
void PortFunc() {}
};
L>Может, сделаешь интерфейсы COM-совместимыми, и заюзаешь ATL? L>В форуме по ATL можно поискать — там рассказывался способ как делать реализации унаследованных друг от друга интерфейсов. В принципе, то же самое можно и без ATL — на случай если приложение невиндовое.
Кстати, NikeByNike предложил именно такое решение, которое юзается для реализации унаследованных друг от друга интерфейсов в ATL.
Здравствуйте, NikeByNike, Вы писали:
NBN>Кстати забыл написать:
Ну это было понятно
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, AndrewJD, Вы писали:
E>>1) Вообще отказаться от наследования интерфейсов. (Проблем никаких, всё понятно, предсказуемо, без накладных расходов, да и совместимо с любыми языками)
AJD>А что предложить в замен?
Что угодно. Напрмиер получать "базу" явным вызовом функции. Или запросом интерфейса (скажем dyn_cast'ом)
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, agaf, Вы писали:
A>Мне бы хотелось реализовать именно вариант с виртуальным наследованием. Правда, нет уверенности, что это возможно в рамках С++.
A>В случае шаблонов непонятно, кто будет реализовывать чисто виртуальный метод IPort::func(), если от IPort никто не наследуется.
У тебя просто не откомпилится IPort — абстрактный класс, если у его наследника не переопределить все его чисто виртуальные функции — не удасца создать объект.
А виртуальное наследование — действительно плохое решение.
Нужно разобрать угил.
Re: множественное наследование
От:
Аноним
Дата:
21.06.07 17:49
Оценка:
Здравствуйте, agaf, Вы писали:
A>Есть два типа портов — PortA и PortB. У них есть как одинаковые методы, так и специфичные. Наружу модуля должны торчать только интерфейсы: IPortA и IPortB. Хочется реализовать это красиво с минимальным повторением кода.
//! Общий интерфейс для всех портов идет нафик :)
// если общих методов много, то определи их как макрос и включай в интерфейсы
//! Специфичный интерфейс порта А
class IPortA
{
virtual void func() = 0;
virtual void funcA() = 0;
};
//! Специфичный интерфейс порта Бclass IPortB : public IPort
{
virtual void func() = 0;
virtual void funcB() = 0;
};
class Port
{
void funcImpl();
};
class PortA: public Port, public IPortA
{
void func() { funcImpl(); }; // делегируем вызов предкуvoid funcA();
};
class PortB: public Port, public IPortB
{
void func() { funcImpl(); }; // делегируем вызов предкуvoid funcB();
};