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

时间:2015-05-24 17:20:31

标签: c++ constructor virtual-inheritance method-signature

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

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中实现了一个奇异的参数构造函数(在实践中从未调用过),它使用正向构造函数来实现最简单的"类中的有效构造函数(保持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中定义第二个构造函数?

  • 有什么缺点?

1 个答案:

答案 0 :(得分:0)

我的回答是:

  • 使用默认构造函数
  • 是的,可以使用enum
  • 否。如果您希望编译器强制您明确调用 A的构造函数,那么您必须声明其他构造函数。但是,如果你没有......使用默认构造函数和init函数只是一个常规的参数化构造函数,
  • 拥有"独特签名的缺点"构造函数:
    • 课程A中的更多代码,
    • 课程B中的更多代码,
    • 课程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); }
};