Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Множественное наследование


Автор: HappyLife 24.12.2007, 16:36
Здраствуйте. В ходе разработки программы возник вопрос. В случае положительного на него ответа мне не придется сильно менять мой код.
Внимание вопрос.

Можно ли как-нибудь сделать вот такую конструкцию?
Код

class A
{
public:
    int GetZ(){/*...*/}
};

class B
{
public:
    virtual int GetZ() = 0;
};

class C : public A,public B
{
/*...*/
};

B * GetC()
{
    return new C;
}
int main()
{
    B * b = GetC();
    b->GetZ(); // Должен вызвать A::GetZ();
    return 0;
}

Автор: bsa 24.12.2007, 16:38
нет. так нельзя.

Автор: Ln78 24.12.2007, 17:02
HappyLife, если под понятие "как-нибудь" подходит такой вариант
Код

class A
{
public:
   int GetZ()
   {
      printf("A\n");
      return 11;
   }
};

class B
{
public:
   virtual int GetZ() = 0;
};


class C : public A,public B
{
public:
  virtual int GetZ()
  {
     printf("C\n");
     return 12;
  }
};

B * GetC()
{
   return new C;
}
int main()
{
   B * b = GetC();
   b->GetZ(); // Должен вызвать A::GetZ();
   ((A*)((C*)&b))->GetZ();
   return 0;
}

то можно smile 

Автор: Earnest 24.12.2007, 18:02
Наверное все-таки смысл в том, чтобы C::GetZ имплементировался через метод A:

Код

class C: public A, public B
{
   virtual int GetZ()
   {
      return A::GetZ();
   }
};

Собственно, нормальный способ - интtрфейс + имплементация. Только вот вызов все же придется делать явно - компилятор не догадается, что из двух методов с одинаковыми именами нужно взять реализованный. Вот если бы оба класса шли от одного корня, да с виртуальным наследованием, да метод GetZ был абстрактным методом, определенным в корневом классе, то тогда компилятор бы догадался (правда, предупреждение все же выдал бы).
Т.е. примерно так:
Код

class Interface1
{
   virtual int GetZ() = 0;
};

class Interface2: virtual public Interface1
{
  // еще виртуальные методы
};

class Impl1: virtual public Interface1
{
   virtual int GetZ() { ... } // реализация
};

class Impl2: public Interface2, public Impl1
{
   // вот здесь переопределять метод GetZ не надо - будет взят метод из Impl1
};

Автор: Random13 26.12.2007, 22:31
Не вижу проблемы. На самом деле в методе класса В написано не что иное, как
{return ptrVTable -> GetZ();} (один из доводов того, что я говорил, что С++ написан на Си).
Виртуальные методы на С++ псевдовиртуальные, просто они перенаправляют в таблицу виртуальных функций. А так - это обычный метод. И на Си можно такую таблицу самому создать и туда перенаправлять запрос.

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

Код

int main()
{
    B * b = GetC();
    b->GetZ(); // Должен вызвать A::GetZ();
    return 0;
}

Просмотрел малость. не не не, если поинтер на b, то вызовется метод класса  b.
В::GetZ();


Единственное как вижу можно выкрутится, если такое нужно - внутри метода класса В делать указатель на А и возвращать его метод, что-то типа
Код

class C;
class A;
class B{
C *pC;
B() { pc = this; }
или
SetpC(C* pc) {pC = pc;}
...
}

int B::GetZ(){ A * a = pC; return a->GetZ();}

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)