C++虚继承小结


虚拟继承是C++语言中一个非常重要但是又比较生僻的存在,它的定义非常简单,但是对于理解C++的继承机制却是非常有用的。笔者最近学习过程中发现对C++的虚拟继承不是很明朗,故在这里对虚继承做个小结。

首先说下遇到的问题吧。代码如下(代码来自于何海涛《程序员面试精选100题第32题)。意图是要设计一个不能被继承的类,类似java中的final。但是又可以生成栈对象,可以像一般的C++类一样使用。

#include<iostream>

using std::endl;

using std::cout;

template <class T> class MakeFinal

{

friend T;

private:

MakeFinal()

{

cout<<"in MakeFinal"<<endl;

}

~MakeFinal(){}

};

 

class FinalClass: virtual public MakeFinal<FinalClass>

{

public:

FinalClass()

{

cout<<"in FinalClass"<<endl;

}

~FinalClass(){}

};

class Try: public FinalClass

{

public:

Try()

{

cout<<"in Try"<<endl;

}

};

这样的确使得FinalClass不能被继承了,原因在于类FinalClass是从类MakeFinal<Final>虚继承过来的,在调用Try的构造函数的时候,会直接跳过FinalClass而直接调用MakeFinal<FinalClass>的构造函数。而Try不是MakeFinal<Final>的友元,所以这里就会出现编译错误。但是如果把虚继承改成一般的继承,这里就没什么问题了。笔者对这里的调用顺序不是很明朗,为了对虚继承有彻底的了解,故做个小结。将从下面几个方向进行总结:1、为何要有虚继承;2、虚继承对于类的对象布局的影响;3、虚基类对构造函数的影响;

1、为什么需要虚继承

由于C++支持多重继承,那么在这种情况下会出现重复的基类这种情况,也就是说可能出现将一个类两次作为基类的可能性。比如像下面的情况

#include<iostream>
using std::cout;
using std::endl;
class Base
{
protected:
int value;
public:
Base()
{
cout<<"in Base"<<endl;
}
};
class DerivedA:protected Base
{
public:
DerivedA()
{
cout<<"in DerivedA"<<endl;
}
};
class DerivedB: protected Base
{
public:
DerivedB()
{
cout<<"in DerivedB"<<endl;
}
};
class MyClass:DerivedA,DerivedB
{
public:
MyClass()
{
cout<<"in MyClass"<<value<<endl;
}
};

编译时的错误如下


这中情况下会造成在MyClass中访问value时出现路径不明确的编译错误,要访问数据,就需要显示地加以限定。变成DerivedA::value或者DerivedB::value,以消除歧义性。并且,通常情况下,像Base这样的公共基类不应该表示为两个分离的对象,而要解决这种问题就可以用虚基类加以处理。如果使用虚继承,编译便正常了,类的结构示意图便如下。

虚继承的特点是,在任何派生类中的virtual基类总用同一个(共享)对象表示,正是如上图所示。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 下一页

相关内容