使用虚拟继承时,是否可以避免冗余基类初始化?

时间:2012-02-21 13:06:26

标签: c++

以下代码说明了我的问题:

struct Base {
    Base(int n) : n(n) {}

    virtual ~Base() = 0;

    int n;
};

Base::~Base() {}

struct A : public virtual Base {
    A(int n) : Base(n) {}

    virtual ~A() = 0;
};

A::~A() {}

struct B : public virtual Base {
    B(int n) : Base(n) {}

    virtual ~B() = 0;
};

B::~B() {}

struct Test : public virtual A, public virtual B {
    Test(int n) : Base(n), A(n), B(n) {} // how to avoid this duplication?
};

int main() {
    Test c(0);
    (void)c;
}

如您所见,Test构造函数必须明确初始化BaseAB。这是正常的吗?或者有办法避免冗余吗?

3 个答案:

答案 0 :(得分:4)

#include <assert.h>

struct Base {
    Base(int n) : n(n) {}

    virtual ~Base() = 0;

    int n;

protected:
    Base() { assert( false ); }
};

Base::~Base() {}

struct A : public virtual Base {
    virtual ~A() = 0;
};

A::~A() {}

struct B : public virtual Base {
    virtual ~B() = 0;
};

B::~B() {}

struct Test : public virtual A, public virtual B {
    Test(int n) : Base(n) {} // how to avoid this duplication?
};

int main() {
    Test c(0);
    (void)c;
}

答案 1 :(得分:2)

没有冗余初始化。虚拟基类的构造只由最派生类的构造函数调用一次。

更新这个问题可以解释为两件事,(1)如何避免在运行时对构造函数进行冗余调用,以及(2)如何避免编写冗余初始化列表。显然,作者的意思是(2)。我在回答(1)。

答案 2 :(得分:2)

首先,您的方案中TestA几乎不需要B,因为AB似乎都不是用作基础。

并且,是的,Base 必须在最派生的类 中初始化。原因很简单,test 的直接基类共享相同的Base子对象 。为了做到这一点,它必须在构造它们中的任何一个之前由最派生的类构造 就个人而言,我一直认为AB也可以构造它,它由声明顺序确定为基类,并拧紧另一个的构造函数。但是当调用不同的构造函数时,这将启用非常微妙的错误,并且基类声明顺序的微妙问题可能会引入令人惊讶的行为更改。 (并不是说我们不会在语言的其他地方出现这样的问题,但少一点可能是件好事。)

但是,请注意,虽然C ++为您提供了所有可能获得的自由,但通常最好是虚拟基类是 抽象类 < em>没有会员数据 ,因此 只是默认构造函数 。由于这将被隐式调用,因此任何派生类都不必为显式调用构造函数而烦恼。