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

Я хочу выполнить виртуальное наследование на следующем очевидном примере:

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?

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

0

Решение

Мои ответы:

  • Используя конструктор по умолчанию,
  • Да, это возможно с enum,
  • Нет. Если вы хотите, чтобы компилятор заставить вас явно позвонить конструктор Aтогда вы должны объявить дополнительный конструктор. Но если вы не … использовать конструктор по умолчанию вместе с init функция или же просто обычный параметризованный конструктор,
  • Недостатки наличия конструктора «уникальная подпись»:
    • больше кода в классе A,
    • больше кода в классе B,
    • больше кода в классе C,
    • больше кода из-за фиктивной структуры.
  • Недостатки наличия c-tor по умолчанию с функцией init:
    • Вы должны помнить, чтобы позвонить 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); }
};
0

Другие решения


По вопросам рекламы [email protected]