浅谈C++中的虚继承

来源:互联网 发布:淘宝企业店收费 编辑:程序博客网 时间:2024/06/03 04:55

何为多重继承?
面向对象编程语言中的多重继承指的是一个类可以同时继承多个父类的行为和特征功能。
就好比一个孩子可以拥有两个甚至更多的父亲。 实
际生活中,一些事物往往会拥有两个或两个以上事物的属性,为了解决这个问题,C++引入了多重继承的概念,C++允许为一个派生类指定多个基类,这样的继承结构被称做多重继承。

但是我们扪心自问,我们真的需要多重继承吗?
不必须需要。但是什么又是我们必须需要的呢?我们可以完全用另一种工作方式代替多重继承,完全可以用另外一种方式代替类,甚至可以代替面向对象语言。但是效率至上,我们不想把有限的声明浪费在无尽的重复代码中。

在C++中,抽象类往往充当接口和一个类可以有多个接口。其他语言 ,譬如说C#,只需有相当于一个纯抽象类的一个独立的名字:一个接口。C#是支持多重继承接口的。 如果有人说多重继承百害无一利,那么你可以轻蔑的回复他:多重继承只是不适合他而已。 下面看一下Standard C++中的例子:

class Base{public:  Base(int n) : value(n)  {     std::cout << "Base(" << n << ")"<< std::endl; // Prints the passed value: Base(N)  }  Base() : value(0)  {     std::cout << "Base()"<< std::endl; // No passed value: Base()  } ~Base() { std::cout << "~Base()"<< std::endl; } int value;};class One : public Base{public:  One() : Base(1)   {     std::cout << "One()"<< std::endl;   } ~One() { std::cout << "~One()"<< std::endl; }};class Two : public Base{public:  Two() : Base(2)  {     std::cout << "Two()"<< std::endl;   } ~Two() { std::cout << "~Two()"<< std::endl; }};class Leaf : public One, public Two{public:  Leaf() : { std::cout << "Leaf()"<< std::endl; } ~Leaf() { std::cout << "~Leaf()"<< std::endl; }};int main(){    Leaf lf;    lf.value = 0; // will cause compilation error    return 0;}

为了避免上述代码的问题,虚继承需要出场了!
加入了关键字virtual,即虚继承。

class One : public virtual Base{};class Two : public virtual Base{};int main(){    Leaf lf;    lf.value = 0; //正确    return 0;}

因为有了virtual,只会调用基类的构造函数一次。 但是问题又来了,编译器是通过类One调用的基类的构造函数还是通过类Two调用的构造函数?
答案是两者都不是。编译器会直接调用Base基类的构造函数。

我们上诉代码类中的构造函数都是public,如果把类的构造函数声明为private情况如何呢?

class Seal{  friend class Final;  Seal() {}};class Final : public virtual Seal{public:  Final() {}};

使用了友元,Final可以调用基类的构造函数。
但是如果从Final类再继承呢?

class Derived : public Final{public:  Derived() {} };

编译器会报错,原因是Derived的构造函数必须调用Seal类的构造函数。而Seal的构造函数为private,所以会报错。
如果去掉了关键字virtual,就不会报错,因为Derived类的构造函数会调用Final的构造函数,而Final类是Seal的友元,即Final可以访问Seal的private构造函数!!

1 0