множественное наследование
От: agaf  
Дата: 20.06.07 15:27
Оценка:
Есть два типа портов — 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


Что я делаю не так?
Re: множественное наследование
От: Константин Л.  
Дата: 20.06.07 15:31
Оценка:
Здравствуйте, agaf, Вы писали:

[]

A>
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 мапиться не будет
Re: множественное наследование
От: Graf Alex Украина http://grafalex.oberon.kiev.ua
Дата: 20.06.07 15:32
Оценка:
Здравствуйте, agaf, Вы писали:

A>Есть два типа портов — PortA и PortB. У них есть как одинаковые методы, так и специфичные. Наружу модуля должны торчать только интерфейсы: IPortA и IPortB. Хочется реализовать это красиво с минимальным повторением кода.

Буквально на прошлой неделе сам с этим боролся...
читать <a href="http://www.rsdn.ru/forum/message/2541889.aspx
Автор: Graf Alex
Дата: 12.06.07
">тут</a>
Re: множественное наследование
От: _Paul Россия  
Дата: 20.06.07 16:45
Оценка:
Здравствуйте, agaf, Вы писали:

Тебе поможет виртуальное наследование:

A>
A>//! Общий интерфейс для всех портов
A>class IPort
A>{
A>  virtual void func() = 0;
A>};

A>//! Специфичный интерфейс порта А
A>class IPortA : public virtual IPort
A>{
A>  virtual void funcA() = 0;
A>};

A>//! Специфичный интерфейс порта Б
A>class IPortB : public virtual IPort
A>{
A>  virtual void funcB() = 0;
A>};

A>class Port : public virtual 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>
Re[2]: множественное наследование
От: NikeByNike Россия  
Дата: 20.06.07 16:50
Оценка: :)
Здравствуйте, _Paul, Вы писали:

_P>Здравствуйте, agaf, Вы писали:


_P>Тебе поможет виртуальное наследование:


Имхо здесь явно проблемы в архитектуре. К сожалению не готов предложить лучшую...
Нужно разобрать угил.
Re[3]: множественное наследование
От: _Paul Россия  
Дата: 20.06.07 17:06
Оценка:
Здравствуйте, NikeByNike, Вы писали:

NBN>Здравствуйте, _Paul, Вы писали:


_P>>Здравствуйте, agaf, Вы писали:


_P>>Тебе поможет виртуальное наследование:


NBN>Имхо здесь явно проблемы в архитектуре. К сожалению не готов предложить лучшую...


Паттерн Bridge?
Re: множественное наследование
От: Erop Россия  
Дата: 20.06.07 17:19
Оценка: -1
Здравствуйте, agaf, Вы писали:

Я бы сделал так:
//! Общий интерфейс для всех портов
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...
А виртуальных баз вообще бы не клал...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: множественное наследование
От: NikeByNike Россия  
Дата: 20.06.07 18:55
Оценка:
Здравствуйте, _Paul, Вы писали:

_P>>>Тебе поможет виртуальное наследование:


NBN>>Имхо здесь явно проблемы в архитектуре. К сожалению не готов предложить лучшую...


_P>Паттерн Bridge?


Не знаю я не вполне уверен, что правильно понимаю задачу. Возможно лучше было бы решить так:

// interface

class IPort
{
    virtual void PortFunc() = 0;
};

class IPortA : public IPort
{
    virtual void PortFuncA() = 0;
};

class IPortB : public IPort
{
    virtual void PortFuncB() = 0;
};

// implementation

template<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>; }
Нужно разобрать угил.
Re[2]: 2 _Paul
От: Erop Россия  
Дата: 20.06.07 20:29
Оценка:
_Paul! А что не так?
Не говоря уже о том, что не соглашаться с сообщением "я бы сделал так" нелогично
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: множественное наследование
От: Erop Россия  
Дата: 21.06.07 06:20
Оценка:
Здравствуйте, NikeByNike, Вы писали:

NBN>IPortA* CreatePortA() { return new PortA<IPortA>; }
NBN>IPortB* CreatePortB() { return new PortB<IPortB>; }


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

Всё-таки мне больше нравится в такой последовательности:

1) Вообще отказаться от наследования интерфейсов. (Проблем никаких, всё понятно, предсказуемо, без накладных расходов, да и совместимо с любыми языками)

2) Виртуально выводиться из базовых интерфейсов

3) Схемы с шаблонами
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: множественное наследование
От: Максим2006 Беларусь  
Дата: 21.06.07 07:16
Оценка:
Здравствуйте, 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() и всё, зачем её в отдельный интерфей выносить?
Re[6]: множественное наследование
От: AndrewJD США  
Дата: 21.06.07 08:32
Оценка:
Здравствуйте, Erop, Вы писали:

E>1) Вообще отказаться от наследования интерфейсов. (Проблем никаких, всё понятно, предсказуемо, без накладных расходов, да и совместимо с любыми языками)


А что предложить в замен?
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re: множественное наследование
От: Left2 Украина  
Дата: 21.06.07 08:47
Оценка:
Может, сделаешь интерфейсы COM-совместимыми, и заюзаешь ATL?
В форуме по ATL можно поискать — там рассказывался способ как делать реализации унаследованных друг от друга интерфейсов. В принципе, то же самое можно и без ATL — на случай если приложение невиндовое.
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[6]: множественное наследование
От: NikeByNike Россия  
Дата: 21.06.07 08:47
Оценка: :)
Здравствуйте, Erop, Вы писали:

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


Ye я в принципе не первый раз такую схему применяю. Подозреваю, что система работы с портами достаточно компактна, так что такая схема будет работать прекрасно...
Кстати забыл написать:
template<class TInterface>
class Port : public TInterface
{
    void PortFunc() {}
};
Нужно разобрать угил.
Re[2]: множественное наследование
От: Left2 Украина  
Дата: 21.06.07 09:09
Оценка: +1
L>Может, сделаешь интерфейсы COM-совместимыми, и заюзаешь ATL?
L>В форуме по ATL можно поискать — там рассказывался способ как делать реализации унаследованных друг от друга интерфейсов. В принципе, то же самое можно и без ATL — на случай если приложение невиндовое.

Кстати, NikeByNike предложил именно такое решение, которое юзается для реализации унаследованных друг от друга интерфейсов в ATL.
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[7]: множественное наследование
От: Erop Россия  
Дата: 21.06.07 09:38
Оценка:
Здравствуйте, NikeByNike, Вы писали:

NBN>Кстати забыл написать:

Ну это было понятно
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: множественное наследование
От: Erop Россия  
Дата: 21.06.07 09:39
Оценка:
Здравствуйте, AndrewJD, Вы писали:

E>>1) Вообще отказаться от наследования интерфейсов. (Проблем никаких, всё понятно, предсказуемо, без накладных расходов, да и совместимо с любыми языками)


AJD>А что предложить в замен?


Что угодно. Напрмиер получать "базу" явным вызовом функции. Или запросом интерфейса (скажем dyn_cast'ом)
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: множественное наследование
От: agaf  
Дата: 21.06.07 12:42
Оценка:
А вот не работает

Здравствуйте, _Paul, Вы писали:

_P>Тебе поможет виртуальное наследование:


A>>
A>>//! Общий интерфейс для всех портов
A>>class IPort
A>>{
A>>  virtual void func() = 0;
A>>};

A>>//! Специфичный интерфейс порта А
A>>class IPortA : public virtual IPort
A>>{
A>>  virtual void funcA() = 0;
A>>};

A>>//! Специфичный интерфейс порта Б
A>>class IPortB : public virtual IPort
A>>{
A>>  virtual void funcB() = 0;
A>>};

A>>class Port : public virtual 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>>
Re[6]: множественное наследование
От: agaf  
Дата: 21.06.07 13:01
Оценка:
Мне бы хотелось реализовать именно вариант с виртуальным наследованием. Правда, нет уверенности, что это возможно в рамках С++.

В случае шаблонов непонятно, кто будет реализовывать чисто виртуальный метод IPort::func(), если от IPort никто не наследуется.

Здравствуйте, Erop, Вы писали:

E>Здравствуйте, NikeByNike, Вы писали:


E>2) Виртуально выводиться из базовых интерфейсов
Re[7]: множественное наследование
От: NikeByNike Россия  
Дата: 21.06.07 13:08
Оценка: +1
Здравствуйте, 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();
};
Re[3]: множественное наследование
От: _Paul Россия  
Дата: 21.06.07 22:31
Оценка:
Здравствуйте, agaf, Вы писали:

A>А вот не работает


Какой компилятор? Проверял на VS2003 — все ок
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.