Я хочу выполнить виртуальное наследование на следующем очевидном примере:
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 (a, b) и C (a, c), потому что параметр a бесполезен в конструкторах B и C для этого конкретного случая виртуального наследования.
Я нашел следующую статью, где Джек Ривз предлагает несколько альтернатив для вызова конструкторов по умолчанию.
http://www.drdobbs.com/cpp/multiple-inheritance-considered-useful/184402074?pgno=2
Цитата:
Если мы должны полностью инициализировать A до того, как B и C могут быть построены, то мы должны выполнить инициализацию с помощью конструктора, и мы вернемся к тому, что я показал сначала. В качестве альтернативы, возможно, вы можете обойтись чем-то вроде следующего:
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 специальный конструктор параметров (никогда не вызываемый на практике), который использует прямой конструктор для «самого простого» допустимого конструктора внутри класса (сохраняйте инкапсуляцию того, что B и C должны вызывать внутри A). Единственный параметр здесь, чтобы дать уникальную подпись этому «ублюдковому» конструктору.
// 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) {}
};
Мои вопросы:
Как избежать вызова слишком большого параметризованного конструктора с виртуальным наследованием?
Можно ли улучшить технику «уникальной подписи», делая что-то еще (например, с помощью enum)?
У кого-нибудь есть лучшая техника, чтобы сделать то же самое без необходимости определять второй конструктор в A?
Какие недостатки?
Мои ответы:
enum
,A
тогда вы должны объявить дополнительный конструктор. Но если вы не … использовать конструктор по умолчанию вместе с init
функция или же просто обычный параметризованный конструктор,A
,B
,C
,init
функция или же параметризованный конструкторПример (незагроможденный) код:
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); }
};