2010-07-18 4 views
1

Странная проблема возникла, когда я пытался «решить» обычную проблему алмазную обычным способом - с использованием виртуального наследования:Алмазные суб-проблема: не-множественное наследование в побочной ветви все еще требуют конструктор класса

A 
/\* both virtual 
B C 
\/
    D 

Однако мой базовый класс а не имеет конструктор по умолчанию, так что я должен был назвать его вручную из D. Однако, когда я пытаюсь добавить класс Е в этот алмаз, как C-наследуется

A 
/\* both virtual 
B C 
\/\ 
    D E 

он по-прежнему необходимо вызвать конструктор из конструктора A в E вручную, то есть C не создает, чтобы создать A из E даже th не существует ни множественного наследования, ни алмаза A-C-E.

class A      
    {public: 
     A (int _N): N(_N) {}; 
     void show() 
     {cout<<"A"<<N;} 
    protected: 
     int N; 
    }; 
class B: public virtual A 
    { public: 
     B(int n): A(2*n) {}; 
     void show() 
     { cout<<"B"<<N;} 
    }; 
class C: public virtual A 
    { public: 
     C(int n): A(3*n) {}; 
     void show() 
     { cout<<"C"<<N;} 
    }; 
class D: public B,C 
    { public: 
     D(): B(1), C(2), A(3) {}; 
     void show() 
     { cout<<"D"<<N;} 
    }; 

class E: public virtual C 
    { public: 
     E(): C(1) {}; 
     void show() 
     { cout<<"E"<<N;} 
    }; 

int main() 
    {D d;  // OK 
    A *a = &d; 
    a->show(); 

    E e;  // NOT OK, no function A::A() to call in E::E() 
    A *a2 = &e; 
    a2->show(); 
    return 0; 
    } 

Можно ли решить эту проблему без вызова конструктора A из E? Мне нужно C, чтобы сделать это правильно :-).

Или это возможно, чтобы не пытаться решить проблему с бриллиантом на всех:

A A 
| | no virtual at all 
B C 
\/\ 
    D E 

и до сих пор пытаются объявить объект класса D с двумя экземплярами, но красноречивая компилятор использовать А С при Colling из D каждый раз? Когда я пытаюсь добавить

using C::A 

в декларацию D она до сих пор производит ошибку однозначна база А.

ответ

2

Можно ли решить эту проблему без вызова конструктора А из Е? Мне нужно C, чтобы сделать это правильно :-).

Конструктор для самого производного класса (в данном случае, E) отвечает за вызов конструктора для любых виртуальных базовых классов.

Конструктор C не может вызвать конструктор A, потому что C не является самым производным классом. Виртуальные базовые классы инициализируются до любых прямых базовых классов, поэтому E должен инициализировать A, прежде чем он сможет инициализировать C.

+0

Спасибо, это понятно, так это точный смысл виртуального наследования? Теперь я вижу. Возможно, мне не нужно виртуальное наследование здесь, к сожалению, это будет неудобно (так как из E есть много производных, и каждый должен вызвать конструктор так же, как C и т. Д.). Может быть, есть способ обойти проблему с алмазом без виртуального наследования (по-разному)? – Nick

+0

@Nick: Трудно сказать с абстрактным примером. Честно говоря, я вообще избегаю сложных иерархий наследования в коде, который я пишу. У кого-то другого может быть хорошее прагматическое решение для общего дела. –

+0

Я думал ... ну, мне не нужно, чтобы C был ребенком А, что в моем конкретном случае. E может быть прямым потомком A (вместе с C). @James, спасибо много снова. – Nick

2

Да, конструктор виртуального базового класса вызовы в отличии от виртуального переопределения функции:

  • вы можете переопределить виртуальную функцию в производном классе;
  • вы должны переопределить виртуальную функцию только в том случае, если функция переопределена в одном из базовых классов, но не в других;
  • Вы не можете переопределить список инициализации для виртуальных базовых классов конструктора базового класса.

Это означает, что:

  • , насколько виртуальное переопределение функции, то, виртуальное наследование не влияет на одиночное наследование вообще;
  • но когда дело доходит до вызовов конструктора базового класса, виртуальное наследование влияет на каждый производный класс.