Множественное наследование

#include<iostream>
using namespace std;

class A

{
   int a;
   int b;
   public:
   void eat()
   {
      cout<<"A::eat()"<<endl;
   }
};

class B: public A
{
   public:
   void eat()
   {

      cout<<"B::eat()"<<endl;

   }

};

class C: public A
{

   public:
   void eat()

   {

      cout<<"C::eat()"<<endl;

   }

};

class D: public B, C
{

};

int foo(A *ptr)
{

ptr->eat();

}
main()
{

D obj;
foo(&(obj.B)); //error. How do i call with D's B part.

}

Вышеуказанный вызов foo является ошибкой времени компиляции. Я хочу вызвать foo с частью B объекта obj, не используя виртуальное наследование. Как я могу это сделать.

Кроме того, в случае виртуального наследования, почему информация о смещении должна храниться в виртуальной таблице. Это можно определить во время самой компиляции. В приведенном выше случае, если мы передадим foo с объектом D, только во время компиляции мы сможем вычислить смещение части A D.

 1800 INFORMATION19 дек. 2008 г., 10:50
Выберите код и затем нажмите кнопку с 1 и 0
 Srikanth19 дек. 2008 г., 10:45
отформатируйте код пожалуйста :)
 user168051230 июл. 2014 г., 17:38
class D: public B, C, Вы действительно хотите, чтобы режим видимости класса B был закрытым? Упоминание ничего не приведет к его наследованию вprivate режим видимости.
 chappar19 дек. 2008 г., 11:01
Люк, ты прав; Я забыл добавить это.
 Luc Touraille19 дек. 2008 г., 10:57
Поскольку foo не является виртуальным, вы получите тот же результат, если вызовете foo с частью B, C или A объекта obj. «A :: eat ()» будет напечатан во всех случаях.
 chappar19 дек. 2008 г., 10:49
Как мне это сделать? В режиме редактирования он отображается правильно.

Ответы на вопрос(4)

Используйте актерский состав -static_cast требуется здесь, чтобы создать иерархию.

main()
{
  D obj;
  foo(static_cast<B*>(&obj));
}

Прежде всего,obj не имеет члена с именем B. Он наследуется от B, что означает, что он наследует всех членов B как своих собственных.

Ты можешь позвонить:

foo(static_cast<B*>(&obj));
заставить это работать.

Я не думаю, что static_cast будет работать.

Когда вы используете функцию foo, все, что знает компилятор, это то, что у вас есть указатель на A, независимо от типа, который вы передали в качестве параметра.

Если вы не используете виртуальное наследование, то я думаю, что нет способа вызвать функцию B из указателя на A.

Решение Вопроса
Наследуя дважды

С двойным наследованием у вас есть неоднозначность - компилятор не может знать, какую из двух баз A вы хотите использовать. Если вы хотите иметь две базы A (иногда вы можете захотеть это сделать), вы можете выбрать между ними приведение к B или C. Наиболее подходящим из приведенных по умолчанию приведений здесь являетсяstatic_cast (как самый слабый из доступных), однако он не является действительно необходимым (он все же сильнее, чем требует ваш случай), так как вы не приводите к производному типу. Обычайsafe_cast шаблон должен делать работу:

/// cast using implicit conversions only
template <class To,class From>
inline To safe_cast( const From &from ) {return from;}

main()
{

  D obj;
  foo(safe_cast<B *>(&obj)); //error. How do i call with D's B part.

}
Типы времени компиляции - используйте шаблоны

Кроме того, в случае виртуального наследования, почему информация о смещении должна храниться в виртуальной таблице. Это можно определить во время самой компиляции. В приведенном выше случае, если мы передадим foo с объектом D, только во время компиляции мы сможем вычислить смещение части A D.

Это заблуждение. Функция foo в том виде, в каком она написана, теперь не имеет информации о типе компиляции о типе ptr, кроме A *, даже если вы передаете B * или C *. Если вы хотите, чтобы foo могла действовать в зависимости от типа прошедшего времени компиляции, вам нужно использовать шаблоны:

template <class TypeDerivedFromA>
int foo(TypeDerivedFromA *ptr)
{
  ptr->eat();
}
Виртуальное Наследование

В ваших вопросах упоминается виртуальное наследство. Если вы хотите использовать виртуальное наследование, вам нужно указать так:

class B: public virtual A ...

class C: public virtual A ...

При этом код будет компилироваться, но в этом решении нет способа выбрать между B :: A или C :: A (есть только один A), поэтому, вероятно, это не то, о чем вы.

Виртуальные функции

Кроме того, ваши вопросы, кажется, смешивают две разные концепции: виртуальное наследование (что означает разделение одного базового класса между двумя промежуточными базовыми классами) и виртуальные функции (что означает, что функция производного класса может вызываться через указатель базового класса). Если вы хотите, чтобы B :: eat вызывался с использованием указателя A, вы можете сделать это без виртуального наследования (фактически виртуальное наследование помешало бы вам сделать это, как описано выше), используя виртуальные функции:

class A
{
   int a;
   int b;

   public:
   virtual void eat()
   {
      cout<<"A::eat()"<<endl;
   }
};

Если виртуальные функции для вас неприемлемы, механизмом компиляции для этого являются шаблоны, как описано выше.

 chappar19 дек. 2008 г., 11:33
Сума, vtable для виртуальных функций и виртуальное наследование одно и то же? Если нет, то что содержит таблица виртуального наследования.
 Suma19 дек. 2008 г., 11:40
При использовании виртуального наследования макет виртуальной таблицы (и механизм вызова виртуальных функций) несколько сложнее. Увидетьen.wikipedia.org/wiki/Virtual_inheritance - но будьте готовы, это сложная тема, и ее понимание требует усилий и терпения.

Ваш ответ на вопрос