构造函数调用层次结构

时间:2013-01-22 10:31:54

标签: c++ constructor call hierarchy

我在类型层次结构中调用构造函数的规则时遇到了棘手的问题。这是我的工作:

class A{
protected:
    int _i;
public:
    A(){i = 0;}
    A(int i) : _i(i){}
    virtual ~A(){}
    virtual void print(){std::cout<<i<<std::endl;}
};

class B : virtual public A{
protected:
    int _j;
public:
    B() : A(){_j = 0;}
    B(int i, int j) : A(i), _j(j){}
    virtual ~B(){}
    virtual void print(){std::cout<<i<<", "<<j<<std::endl;}
};

class C : virtual public B{
protected:
    int _k;
public:
    C() : B(){_k = 0;}
    C(int i, int j, int k} : B(i,j), _k(k){}
    virtual ~C(){}
    virtual void print(){std::cout<<i<<", "<<j<<", "<<k<<std::endl;}
};

int main(){
    C* myC = new C(1,2,3);
    myC->print();
    delete myC;
    return 0;
}

现在,我想让新的C(1,2,3)调用B(1,2)的构造函数,然后依次调用构造函数A(1)来存储_i = 1,_j = 2 ,_k = 3。在创建类C的实例myC时,出于某种原因我不明白,但是,要调用的第一个构造函数是A的标准构造函数,即A :: A();这显然会导致错误的结果,因为受保护的变量_i被赋值为0.从不调用构造函数A(1)。为什么会这样?我发现这非常直观。有没有办法避免显式调用类型层次结构中的所有构造函数来实现所需的行为?

请求帮助!

4 个答案:

答案 0 :(得分:7)

你真的需要virtual继承吗? 您遇到了问题,因为首先会调用第一个虚拟基础ctor,但是当您从C继承B时,您不会指定任何问题(后者已经A虚拟继承,所以默认被称为。)

一种解决方案是删除虚拟继承......如Arne Mertz的答案所述。 另一个(如果你真的想要虚拟继承)是从A ctor明确地调用C

C(int i, int j, int k} : A(i), B(i,j), _k(k){}

答案 1 :(得分:6)

这是因为您使用了虚拟继承,这在存在多个继承时才有意义。只是正常继承,一切都会如你所愿。

答案 2 :(得分:5)

使用虚拟继承时,派生程度最高的类必须直接调用其所有虚拟基础的构造函数。在这种情况下,C的构造函数必须调用BA的构造函数。由于您只调用B构造函数,因此它使用默认的A构造函数。 B构造函数调用另一个A构造函数并不重要:因为它是一个虚拟基类,所以忽略此调用。

您有两种解决此问题的方法:显式调用A(int)构造函数:

C(int i, int j, int k} : A (i), B(i,j), _k(k){}

或使用普通继承而不是虚拟。

答案 3 :(得分:0)

为什么要声明虚拟继承?如果从B类中删除虚拟关键字:虚拟公共A {...那么您的代码将正常工作。通过声明虚拟A,C将直接调用A()。如果删除虚拟,那么C将不会调用A()。