множественное наследование интерфейсов.
От: programmater  
Дата: 18.05.06 12:24
Оценка:
Есть несколько объявлений интерфейсов, каждый из которых имеет одинаковую по сигнатуре функцию:
class IFace1
{
  public:
   virtual int GetCount() const=0;
   //--другие функции интерфейса IFace1
};

class IFace2
{
  public:
   virtual int GetCount() const=0;
   //--другие функции интерфейса IFace2
};

и т.д. И так получается, что я хочу, чтобы имплементировал все эти интерфейсы один класс (читай компонент, хотя к COM описываемая ситуевина не относится), т.к. только в этом классе имеется достаточно информации (в данных этого класса), чтобы реализовывать эти интерфейсы. Так вот, по сути IFace1::GetCount() и IFace2::GetCount() — это разные функции и возвращать они должны разные значения. Но если я сделаю
class MyCoolMultipleIFacesImpl: public IFace1, public IFace2, ... ,public IFaceN
{
  public:
    virtual int GetCount() const {return чего-то там такое;}
};

то великий и могучий компилятор засунет указатель на этот ГетКаунт во все реализуемые интерфейсы. Собственно вопрос в следующем: как написать разные реализации функций для разных реализуемых интерфейсов в одном классе?
На вопросы типа "зачем так надо?" отвечать долго, здесь я ситуацию упрощаю, привожу только суть проблемы. Все разумные приписки к имени функций уже сделаны (остались разве что приписки в стиле __AFX_GUID__, что, ИМХО, не выход). Можно ли как-то решить эту проблему или это глобально? Что по этому поводу думает уважаемый All?
Re: множественное наследование интерфейсов.
От: rg45 СССР  
Дата: 18.05.06 12:29
Оценка:
"programmater" <34509@users.rsdn.ru> wrote in message news:1904454@news.rsdn.ru...
> Есть несколько объявлений интерфейсов, каждый из которых имеет одинаковую по сигнатуре функцию:
>
> class IFace1
> {
>  public:
>   virtual int GetCount() const=0;
>   //--другие функции интерфейса IFace1
> };
> 
> class IFace2
> {
>  public:
>   virtual int GetCount() const=0;
>   //--другие функции интерфейса IFace2
> };
>

> и т.д. И так получается, что я хочу, чтобы имплементировал все эти интерфейсы один класс (читай компонент, хотя к COM описываемая ситуевина не относится), т.к. только в этом классе имеется достаточно информации (в данных этого класса), чтобы реализовывать эти интерфейсы. Так вот, по сути IFace1::GetCount() и IFace2::GetCount() — это разные функции и возвращать они должны разные значения. Но если я сделаю
>
> class MyCoolMultipleIFacesImpl: public IFace1, public IFace2, ... ,public IFaceN
> {
>  public:
>    virtual int GetCount() const {return чего-то там такое;}
> };
>

> то великий и могучий компилятор засунет указатель на этот ГетКаунт во все реализуемые интерфейсы. Собственно вопрос в следующем: как написать разные реализации функций для разных реализуемых интерфейсов в одном классе?
> На вопросы типа "зачем так надо?" отвечать долго, здесь я ситуацию упрощаю, привожу только суть проблемы. Все разумные приписки к имени функций уже сделаны (остались разве что приписки в стиле __AFX_GUID__, что, ИМХО, не выход). Можно ли как-то решить эту проблему или это глобально? Что по этому поводу думает уважаемый All?

Может перейти от наследования к агрегированию?
Posted via RSDN NNTP Server 2.0
--
Не можешь достичь желаемого — пожелай достигнутого.
Re: множественное наследование интерфейсов.
От: Greg Zubankov СССР  
Дата: 18.05.06 12:36
Оценка: 24 (5)
Здравствуйте, programmater, Вы писали:

Тебе поможет идиома NVI (Non Virtual Interface):

class IFace1
{
public:
  int GetCount() const
  {
    return GetCountIFace1();
  }

protected:
  virtual int GetCountIFace1() const=0;
  //--другие функции интерфейса IFace1
};

class IFace2
{
public:
  int GetCount() const
  {
    return GetCountIFace2();
  }

protected:
  virtual int GetCountIFace2() const=0;
  //--другие функции интерфейса IFace2
}; 

class MyCoolMultipleIFacesImpl: public IFace1, public IFace2
{
protected:
  virtual int GetCountIFace1() const {return 0;}
  virtual int GetCountIFace2() const {return 1;}
};
Re[2]: множественное наследование интерфейсов.
От: programmater  
Дата: 18.05.06 13:03
Оценка:
Здравствуйте, Greg Zubankov, Вы писали:

GZ>Тебе поможет идиома NVI (Non Virtual Interface):


class IFace1
{
public:
  int GetCount() const
  {
    return GetCountIFace1();
  }
  //--другие функции интерфейса IFace1

protected:
  virtual int GetCountIFace1() const=0;
};

class IFace2
{
public:
  int GetCount() const
  {
    return GetCountIFace2();
  }
  //--другие функции интерфейса IFace2

protected:
  virtual int GetCountIFace2() const=0;
}; 

class MyCoolMultipleIFacesImpl: public IFace1, public IFace2
{
  protected:
    virtual int GetCountIFace1() const {return 0;}
    virtual int GetCountIFace2() const {return 1;}
};



Уже ближе. Если не будет других идей — сойдет как решение. Спасибо. У народа другие идеи есть?
Re[2]: множественное наследование интерфейсов.
От: programmater  
Дата: 18.05.06 13:07
Оценка:
Здравствуйте, rg45, Вы писали:

[кусь]
R>Может перейти от наследования к агрегированию?
Да...вроде ничего не мешает, тока никрасиво. Но насколько я знаю, невозможно создать экземпляр класса, имеющего чисто виртуальные функции (т.е. не имеющие реализации). А реализовать эти функции может только этот самый великий и могучий класс-имплементатор. Как здесь поможет агрегирование?
Re[3]: множественное наследование интерфейсов.
От: rg45 СССР  
Дата: 18.05.06 13:11
Оценка:
"programmater" <34509@users.rsdn.ru> wrote in message news:1904928@news.rsdn.ru...
> Здравствуйте, rg45, Вы писали:
>
> [кусь]
> R>Может перейти от наследования к агрегированию?
> Да...вроде ничего не мешает, тока никрасиво. Но насколько я знаю, невозможно создать экземпляр класса, имеющего чисто виртуальные функции (т.е. не имеющие реализации). А реализовать эти функции может только этот самый великий и могучий класс-имплементатор. Как здесь поможет агрегирование?

Мне как-то в руки попала книжка Дейла Роджерсона "Основы COM". Там обсуждаются именно эти вопросы, о доступе к интерфейсам, о подсчете ссылок, как сделать лучше и чего делать не стоит. Там приводится пример, где объединение интерфейсов делается сначала с помощью наследования, а далее это же самое делается с помощью агрегирования. Мне это книжка очень понравилась, читается на одном дыхании, вот небольшая цитата оттуда:

Правила и соглашения QueryInterface
В этом разделе представлены некоторые правила, которым должны следовать все реализации QueryInterface.
Если их выполнять, клиент сможет узнать о компоненте достаточно, чтобы (надеяться) управлять им и
использовать его в своих целях. Без этих правил поведение QueryInterface было бы неопределенным, и писать
программы было бы невозможно.
— Вы всегда получаете один и тот же IUnknown.
— Вы можете получить интерфейс снова, если смогли получить его раньше.
— Вы можете снова получить интерфейс, который у Вас уже есть.
— Вы всегда можете вернуться туда, откуда начали.
— Если Вы смогли попасть куда-то хоть откуда-нибудь, Вы можете попасть туда откуда угодно.

Posted via RSDN NNTP Server 2.0
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: множественное наследование интерфейсов.
От: Bell Россия  
Дата: 18.05.06 13:12
Оценка:
Здравствуйте, programmater, Вы писали:

P>Уже ближе. Если не будет других идей — сойдет как решение. Спасибо. У народа другие идеи есть?


У VC7 есть такое вот нестандартное расширение:

struct I1
{
   virtual void f() = 0;
};

struct I2
{
   virtual void f() = 0;
};

struct test : public I1, public I2
{
   virtual void I1::f() { cout << "I1::f\n"; }
   virtual void I2::f() { cout << "I2::f\n"; }
};

int main()
{
   test t;
   I1* p1 = &t;
   I2* p2 = &t;

   p1->f();
   p2->f();

   return 0;
}


Взято здесь
Автор: kov_serg
Дата: 21.04.06
Любите книгу — источник знаний (с) М.Горький
Re[4]: Про Роджерсона
От: programmater  
Дата: 18.05.06 13:18
Оценка:
Здравствуйте, rg45, Вы писали:


R>"programmater" <34509@users.rsdn.ru> wrote in message news:1904928@news.rsdn.ru...

>> Здравствуйте, rg45, Вы писали:
>>
>> [кусь]
>> R>Может перейти от наследования к агрегированию?
>> Да...вроде ничего не мешает, тока никрасиво. Но насколько я знаю, невозможно создать экземпляр класса, имеющего чисто виртуальные функции (т.е. не имеющие реализации). А реализовать эти функции может только этот самый великий и могучий класс-имплементатор. Как здесь поможет агрегирование?

R>Мне как-то в руки попала книжка Дейла Роджерсона "Основы COM". Там обсуждаются именно эти вопросы, о доступе к интерфейсам, о подсчете ссылок, как сделать лучше и чего делать не стоит. Там приводится пример, где объединение интерфейсов делается сначала с помощью наследования, а далее это же самое делается с помощью агрегирования. Мне это книжка очень понравилась, читается на одном дыхании, вот небольшая цитата оттуда:

R>

R>Правила и соглашения QueryInterface
R>В этом разделе представлены некоторые правила, которым должны следовать все реализации QueryInterface.
R>Если их выполнять, клиент сможет узнать о компоненте достаточно, чтобы (надеяться) управлять им и
R>использовать его в своих целях. Без этих правил поведение QueryInterface было бы неопределенным, и писать
R>программы было бы невозможно.
R>- Вы всегда получаете один и тот же IUnknown.
R>- Вы можете получить интерфейс снова, если смогли получить его раньше.
R>- Вы можете снова получить интерфейс, который у Вас уже есть.
R>- Вы всегда можете вернуться туда, откуда начали.
R>- Если Вы смогли попасть куда-то хоть откуда-нибудь, Вы можете попасть туда откуда угодно.

Сабж читал, правда насчет "одного дыхания" не согласен. Дочитал до фабрик и IClassFactory и сдох. Надолго. Потом этот материал изучал уже по другим источникам. Приведенную цитату читал (если не ошибаюсь, она где-то недалеко от начала), но пока не понимаю, как в моем случае поможет агрегирование. Роджерсон описывает другую ситуацию: когда у тебя уже есть компонент, который реализует нужный тебе интерфейс. А у меня такого компонента нет, так что агрегировать мне нечего. Или я не правильно понял Роджерсона?
Re[4]: множественное наследование интерфейсов.
От: programmater  
Дата: 18.05.06 13:21
Оценка:
Здравствуйте, Bell, Вы писали:

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


P>>Уже ближе. Если не будет других идей — сойдет как решение. Спасибо. У народа другие идеи есть?


B>У VC7 есть такое вот нестандартное расширение:


B>
B>struct I1
B>{
B>   virtual void f() = 0;
B>};

B>struct I2
B>{
B>   virtual void f() = 0;
B>};

B>struct test : public I1, public I2
B>{
B>   virtual void I1::f() { cout << "I1::f\n"; }
B>   virtual void I2::f() { cout << "I2::f\n"; }
B>};

B>int main()
B>{
B>   test t;
B>   I1* p1 = &t;
B>   I2* p2 = &t;

   p1->>f();
   p2->>f();

B>   return 0;
B>}
B>


B>Взято здесь
Автор: kov_serg
Дата: 21.04.06

Вот что-то типа этого я и хотел. Тока пишу на VC6. Там такое прокатит?
Re[5]: множественное наследование интерфейсов.
От: Bell Россия  
Дата: 18.05.06 13:33
Оценка:
Здравствуйте, programmater, Вы писали:

P>Вот что-то типа этого я и хотел. Тока пишу на VC6. Там такое прокатит?

Нет.
Любите книгу — источник знаний (с) М.Горький
Re[3]: множественное наследование интерфейсов.
От: Programmierer AG  
Дата: 18.05.06 14:37
Оценка: +1
Здравствуйте, programmater, Вы писали:
P>Уже ближе. Если не будет других идей — сойдет как решение. Спасибо. У народа другие идеи есть?
Вариация на тему. Допустим, интерфейсы менять нельзя.

P>
P>class IFace1
P>{
P>public:
P>  virtual int GetCount() const=0;
P>};

P>class IFace2
P>{
P>public:
P>  virtual int GetCount() const=0;
P>};

class IFace1Redirect : public IFace1
{
public:
  virtual int GetCount() const {
    return GetCountIFace1();
  }
protected:
  virtual int GetCountIFace1()const=0;
};

class IFace2Redirect : public IFace2
{
public:
  virtual int GetCount() const {
    return GetCountIFace2();
  }
protected:
  virtual int GetCountIFace2()const=0;
};



P>class MyCoolMultipleIFacesImpl: public IFace1Redirect, public IFace2Redirect
P>{
P>  protected:
P>    virtual int GetCountIFace1() const {return 0;}
P>    virtual int GetCountIFace2() const {return 1;}
P>};
P>
Re: множественное наследование интерфейсов.
От: minorlogic Украина  
Дата: 18.05.06 15:39
Оценка: 1 (1)
Здравствуйте, programmater, Вы писали:

А так ?

class Counted
{
   virtual int GetCount() const=0;
};


class IFace1 : public virtual Counted
{
};

class IFace2 : public virtual Counted
{
};

class  CountedImplementation : public virtual Counted
{
 virtual int GetCount() const { return 0; }
};

class MyCoolMultipleIFacesImpl: public  virtual IFace1, public  virtual IFace2, ... ,public virtual IFaceN, public  virtual CountedImplementation 
{
};


Ромбовидное наследованеи
Ищу работу, 3D, SLAM, computer graphics/vision.
Re: множественное наследование интерфейсов.
От: Шахтер Интернет  
Дата: 18.05.06 20:17
Оценка: 1 (1) +1
Здравствуйте, programmater, Вы писали:

/* main.cpp */ 

#include <iostream>

using namespace std;

struct IFace1
 {
  virtual int GetCount() const =0;
 };

struct IFace2
 {
  virtual int GetCount() const =0;
 };
 
struct IFace1_adapter : IFace1
 {
  virtual int GetCount_IFace1() const =0;
  
  virtual int GetCount() const { return GetCount_IFace1(); }
 }; 

struct IFace2_adapter : IFace2
 {
  virtual int GetCount_IFace2() const =0;
  
  virtual int GetCount() const { return GetCount_IFace2(); }
 }; 
 
struct Impl : IFace1_adapter , IFace2_adapter
 {
  virtual int GetCount_IFace1() const { return 1; }
  
  virtual int GetCount_IFace2() const { return 2; }
 };
 
/* main() */   

int main()
 {
  Impl impl;
  IFace1 *if1=&impl;
  IFace2 *if2=&impl;
  
  cout << "if1->GetCount()=" << if1->GetCount()
       << "\nif2->GetCount()=" << if2->GetCount() << endl ;
 
  return 0;
 }
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[5]: Про Роджерсона
От: rg45 СССР  
Дата: 18.05.06 21:16
Оценка:
"programmater" <34509@users.rsdn.ru> wrote in message news:1905029@news.rsdn.ru...

> Сабж читал, правда насчет "одного дыхания" не согласен. Дочитал до фабрик и IClassFactory и сдох. Надолго. Потом этот материал изучал уже по другим источникам. Приведенную цитату читал (если не ошибаюсь, она где-то недалеко от начала), но пока не понимаю, как в моем случае поможет агрегирование. Роджерсон описывает другую ситуацию: когда у тебя уже есть компонент, который реализует нужный тебе интерфейс. А у меня такого компонента нет, так что агрегировать мне нечего. Или я не правильно понял Роджерсона?


Да все правильно, вроде. Агрегация в данном случае — это оффтопик, прошу меня извинить, но все же я выскажусь. Все таки, идея с наследованием мне кажется не очень удачной в данном случае. Потенциально возможен конфликт двух несовместимых интерфейсов,. например, если в разных интерфейсах две одноименные функции будут отличаться только возвращаемым значением. В этом случае прийдется прибегать, например, к адаптеру, предложенному Шахтером
Автор: Шахтер
Дата: 19.05.06
. При этом наследование оказывается достаточно бесполезным: вызвать эти функции можно будет только через преобразование к одному из базовых интерфейсов, а для производного интерфеса нельзя. Следовательно производный интерфейс не является видом и не работает подобно ни одному из базовых. Таким образом, налицо все предпосылки для замены наследования агрегированием с доступом к интерфейсам посредством QueryInterface() или чего то похожего.
Posted via RSDN NNTP Server 2.0
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: множественное наследование интерфейсов.
От: programmater  
Дата: 19.05.06 10:00
Оценка:
Здравствуйте, minorlogic, Вы писали:

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


M> А так ?


M>
M>class Counted
M>{
M>   virtual int GetCount() const=0;
M>};


M>class IFace1 : public virtual Counted
M>{
M>};

M>class IFace2 : public virtual Counted
M>{
M>};

M>class  CountedImplementation : public virtual Counted
M>{
M> virtual int GetCount() const { return 0; }
M>};

M>class MyCoolMultipleIFacesImpl: public  virtual IFace1, public  virtual IFace2, ... ,public virtual IFaceN, public  virtual CountedImplementation 
M>{
M>};

M>


M>Ромбовидное наследование

Не, это совсем не то. Ты предлагаешь то, от чего я всеми силами хочу уйти. Я хочу, чтобы GetCount() были разными. А ты наоборот — свел все не только в одну функцию, но и в один интерфейс вообще .
Re: множественное наследование интерфейсов.
От: programmater  
Дата: 19.05.06 10:25
Оценка:
Спасибо всем ответившим. В общем, подумав над тем, что мне тут насоветовали, родил решение. Точнее 2. Первое решение для случая, когда объявления интерфейсов IFace1 — IFaceN можно немножко менять (заменять virtual на не-virtual и добавлять другие функции) — это Non Virtual Interface, предложенное здесь
Автор: Greg Zubankov
Дата: 18.05.06
. Если же интерфейс менять нельзя, то у меня получился гибрид на тему того же NVI и курьёзли рикурсив темплейтс (уже не знаю кем и когда придуманными, но активно и по делу использующимися в WTL). Решение следующего вида. IFace1 — IFaceN оставляем как были (с чисто виртуальными функциями int GetCount() const=0)
Далее пишем переходники-имплементаторы вида:

template<class RealImpl> class IFace_1_LocImpl : public IFace1
{
  public:
    virtual int GetCount() const {return static_cast<RealImpl*>(this)->GetCountIFace1Impl();}
};

template<class RealImpl> class IFace_2_LocImpl : public IFace2
{
  public:
    virtual int GetCount() const {return static_cast<RealImpl*>(this)->GetCountIFace2Impl();}
};

И наконец наследуем наш могучий класс-имплементатор от всех этих переходников — имплементаторов:
class MyCoolMultipleIFacesImpl : public IFace_1_LocImpl<MyCoolMultipleIFacesImpl> , 
                                 public IFace_2_LocImpl<MyCoolMultipleIFacesImpl>,...
                                 public IFace_N_LocImpl<MyCoolMultipleIFacesImpl>
{
  int GetCountIFace1Impl() const {return Counter_1;}
  int GetCountIFace2Impl() const {return Counter_2;}
  ...
  int GetCountIFaceNImpl() const {return Counter_N;}
};

Здесь функции-реализации GetCountIFace1Impl() — GetCountIFaceNImpl() НЕ виртуальные, так что никакого ран-тайм оверхеда не будет. Клиенты получают реальный интерфейс (с реальной виртуальной функцией GetCount()), так что код даже скомпилированных клиентов не изменится. Оценяйте
Если же таких жестких требований нет, то вполне сгодится NVI, там тоже нет ран-тайм оверхеда. Просто немного поменяются объявления интерфейсов и все.
В общем всем спасибо. Хотя, если еще есть идеи — не откажусь
Re: множественное наследование интерфейсов.
От: Tom Россия http://www.RSDN.ru
Дата: 19.05.06 10:44
Оценка:
struct IFace1
{
    virtual long GetCount() = 0;
};

struct IFace2
{
    virtual long GetCount() = 0;
};

struct IFace1Impl : public IFace1
{
    virtual long GetCount(){return 1;}
};

struct IFace2Impl : public IFace2
{
    virtual long GetCount(){return 2;}
};

struct MyCoolMultipleIFacesImpl : public IFace1Impl, public IFace2Impl
{
};

int _tmain(int argc, _TCHAR* argv[])
{
    MyCoolMultipleIFacesImpl impl;
    long l1 = ((IFace1*)(&impl))->GetCount(); //l1 = 1
    long l2 = ((IFace2*)(&impl))->GetCount(); //l2 = 2

    return 0;
}
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
Народная мудрось
всем все никому ничего(с).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.