2015-05-24 3 views
0

Я хочу, чтобы выполнить виртуальное наследование со следующим очевидным примером:Как избежать вызова слишком большого параметризованного конструктора с виртуальным наследованием?

class A 
{ 
public: 
    A(int a) : m_a(a) {} 
private: 
    int m_a; 
}; 

class B : virtual public A 
{ 
public: 
    B(int a, int b) : A(a), m_b(b) {} 
private: 
    int m_b; 
}; 

class C : virtual public A 
{ 
public: 
    C(int a, int c) : A(a), m_c(c) {} 
private: 
    int m_c; 
}; 

class D : public B, public C 
{ 
public: 
    D(int a, int b, int c) : A(a), B(a, b), C(a, c) {} 
}; 

Но я не хочу называть B (а, Ь) и С (а, с), поскольку параметром а бесполезно B и C для этого конкретного случая виртуального наследования.

Я нашел следующую статью, где Джек Ривз предлагает несколько альтернатив, чтобы вызвать конструкторы по умолчанию.

http://www.drdobbs.com/cpp/multiple-inheritance-considered-useful/184402074?pgno=2

Цитата:

Если мы должны полностью инициализировать перед В и С могут быть построены, то мы должны сделать инициализацию с конструктором, и мы вернулись к тому, что я показал в первой. В качестве альтернативы, возможно, вы можете получить что-то вроде следующего:

class B : public virtual A { // class C is similar 
public: 
    B(int x) : A(x) {} 
protected: 
    B() : A(0) {} 
}; 
class D : public B, public C { 
public: 
    D(int x) : A(x) {} // B and C are default constructed 
}; 

Конец цитаты.

Итак, я сохранил эту идею защищенного конструктора, но я не хочу использовать конструктор по умолчанию. Я реализовал конструктор сингулярных параметров в A (никогда не называемый на практике), которые используют конструктор forward для «самого простого» допустимого конструктора внутри класса (сохраняйте инкапсуляцию того, что B и C должны вызвать внутри A). Единственный параметр здесь, чтобы дать уникальную подпись этому конструктору «bastard».

// new way 
namespace VIRTUAL_INHERITANCE { 
struct NEVER_CALLED {}; 
} 

class A 
{ 
public: 
    A(int a) : m_a(a) {} 
protected: 
    A(VIRTUAL_INHERITANCE::NEVER_CALLED vinc) : A(0) {} 
private: 
    int m_a; 
}; 

class B : virtual public A 
{ 
public: 
    B(int a, int b) : A(a), m_b(b) {} 
protected: 
    B(int b) : A(VIRTUAL_INHERITANCE::NEVER_CALLED()), m_b(b) {} 
private: 
    int m_b; 
}; 

class C : virtual public A 
{ 
public: 
    C(int a, int c) : A(a), m_c(c) {} 
protected: 
    C(int c) : A(VIRTUAL_INHERITANCE::NEVER_CALLED()), m_c(c) {} 
private: 
    int m_c; 
}; 

class D : public B, public C 
{ 
public: 
    D(int a, int b, int c) : A(a), B(b), C(c) {} 
}; 

Мои вопросы:

  • Как избежать вызова слишком много параметризированный конструктор, с виртуальным наследованием?

  • Возможно ли улучшить технику «уникальной подписи», сделав что-то еще (с перечислением, например)?

  • Есть ли у кого-то лучшая техника, чтобы сделать то же самое без необходимости определять второй конструктор в A?

  • Каковы недостатки?

+0

Цитирование: Очевидное не компилируется: Класс D: B, публичное общественное C { общественности: D (INT х): В (х), С (х) {}} ; Это вызывает ошибку, жалуясь на отсутствие конструктора по умолчанию для A. Для выполнения этой работы мы должны написать: D (int x): A (x), B (x), C (x) {} Хотя это действительно работает, это выглядит глупо, потому что вызов инициализатора для A игнорируется в конструкторах B и C при вызове для объекта D. – Cevik

+0

Какую проблему программирования вы на самом деле пытаетесь решить? – gnasher729

+0

Вы прочитали весь пост? Мои вопросы завершаются. – Cevik

ответ

0

Мои ответы:

  • Используя конструктор по умолчанию,
  • Да, можно с enum,
  • No. Если вы хотите, чтобы компилятор силы на вас явно вызвать конструктор A, тогда вы должны объявить дополнительный конструктор. Но если вы не ...использовать конструктор по умолчанию вместе с init функцией или просто обычная, параметрическая конструктор,
  • Недостатков наличия «уникальная подпись» конструктор:
      более код в классе A
    • ,
    • больше коды в классе B,
    • еще код в классе C,
    • еще код из-за фиктивной структуры.
  • Недостатками имеющий По умолчанию C-TOR с "INIT" функции:
    • вы должны помнить, чтобы позвонить init функция или параметризованная конструктор

Sample (загромождать код):

class A 
{ 
public: 
    A(int a) : m_a(a) {} 
protected: 
    A() = default; 
    void initA(int a) { m_a = a; } // optional 
private: 
    int m_a; 
}; 

class B : virtual public A 
{ 
public: 
    B(int a, int b) : A(a), m_b(b) {} 
protected: 
    B(int b) : m_b(b) {} 
private: 
    int m_b; 
}; 

class C : virtual public A 
{ 
public: 
    C(int a, int c) : A(a), m_c(c) {} 
protected: 
    C(int c) : m_c(c) {} 
private: 
    int m_c; 
}; 

class D : public B, public C 
{ 
public: 
    D(int a, int b, int c) : A(a), B(b), C(c) {} 
    // or optionally: 
    D(int a, int b, int c) : B(b), C(c) { initA(a); } 
}; 
+0

Я не совсем понимаю, зачем вам нужна функция initA. Почему бы вам просто не называть 'D (int a, int b, int c): A (a), B (b), C (c) {}'? – dyp

+0

На самом деле, это то же самое :), потому что нужно называть это явно. –

+0

Не совсем. В сценариях реальной жизни 'B' &' C' часто полагаются на 'a', которые установлены правильно. Отсрочка initalizion не является хорошей стратегией ... –

Смежные вопросы