如何避免使用虚拟继承调用过多的参数化构造函数?

How to avoid calling a too much parameterized constructor, with virtual inheritance?

我想使用以下明显的示例执行虚拟继承:

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 构造函数中对于虚拟继承的这种特殊情况是无用的。

我找到了以下文章,其中 Jack Reeves 提出了一些替代方法来调用默认构造函数。

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

引用:

如果我们必须在构造B和C之前完全初始化A,那么我们必须用构造函数进行初始化,我们又回到了我一开始展示的内容。或者,也许您可​​以通过以下方式解决问题:

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 中实现了一个单参数构造函数(在实践中从未调用过),它使用前向构造函数指向 class 中的 "simpliest" 有效构造函数(保持 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) {}
};

我的问题是:

我的答案是:

  • 使用默认构造函数,
  • 是的,可以使用 enum
  • 没有。如果您希望编译器强制您显式调用 A 的构造函数,那么您必须声明 附加构造函数。但是,如果您不...使用默认构造函数和 init 函数 只是一个常规的参数化构造函数,
  • 具有"unique signature"构造函数的缺点:
    • 更多代码在 class A,
    • 更多代码在 class B,
    • 更多代码在 class C,
    • 由于虚拟结构,代码较多。
  • 使用 "init" 函数的默认 c-tor 的缺点:
    • 你必须记得调用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); }
};