7

我在调用类型层次结构中的构造函数的规则时遇到了麻烦。这是我所做的:

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;
}

现在,我想让 new 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

4 回答 4

7

你真的需要在virtual这里继承吗?您遇到了一个问题,因为将首先调用第一个虚拟基础 ctor,但是您在继承C自时没有指定任何内容B(后者已经A虚拟继承,因此调用了默认值)。

一种解决方案是删除虚拟继承……正如 Arne Mertz 的回答中提到的那样。另一个(如果你真的想要虚拟继承)是ACctor显式调用:

C(int i, int j, int k} : A(i), B(i,j), _k(k){}
于 2013-01-22T10:41:06.793 回答
6

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

于 2013-01-22T10:36:35.253 回答
6

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

你有两种方法可以解决这个问题:显式调用A(int)构造函数:

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

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

于 2013-01-22T10:42:08.330 回答
0

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

于 2016-09-23T15:14:30.937 回答