编译器提示调用f方法错误。而采用

ii.istream::f();

  编译通过,并且会调用istream类vptr指向的f()方法。 前面说了这么多,在实际的应用中虚拟继承的胡乱使用,更是会导致继承顺序以及基类构造顺序的混乱。如下面的代码:

class B1
{
public:
    B1(){cout<<"B1::B1()!<"<<endl;}
    void f() {cout<<"i'm here!"<<endl;}
};

class V1: public B1
{
public:
    V1(){cout<<"V1::V1()!<"<<endl;}
};

class D1: virtual public V1
{
public:
    D1(){cout<<"D1::D1()!<"<<endl;}
};

class B2
{
public:
    B2(){cout<<"B2::B2()!<"<<endl;}
};

class B3
{
public:
    B3(){cout<<"B3::B3()!<"<<endl;}
};

class V2:public B1, public B2
{
public:
    V2(){cout<<"V2::V2()!<"<<endl;}
};

class D2:virtual public V2, public B3
{
public:
    D2(){cout<<"D2::D2()!<"<<endl;}
};

class M1
{
public:
    M1(){cout<<"M1::M1()!<"<<endl;}
};

class M2
{
public:
    M2(){cout<<"M2::M2()!<"<<endl;}
};

class X:public D1, public D2
{
    M1 m1;
    M2 m2;
};
int main(int argc, const char * argv[])
{
    X x;
};

  上面的代码是来自《Exceptional C++ Style》中关于继承顺序的一段代码。可以看到,上面的代码继承关系非常复杂,而且层次不是特别的清楚。而虚继承的加入更是让继承结构更加无序。不管怎么样,我们还是可以根据c++的标准来分析上面代码的构造顺序。c++对于创建一个类类型的初始化顺序是这样子的:

  1、上层派生类的构造函数负责调用虚基类子对象的构造函数。所有虚基类子对象会按照深度优先、从左到右的顺序进行初始化;

  2、直接基类子对象按照它们在类定义中声明的顺序被一一构造起来;

  3、非静态成员子对象按照它们在类定义体中的声明的顺序被一一构造起来;

  4、上层派生类的构造函数体被执行。