虚拟继承

virtual(虚拟继承-虚函数)
★从语义上来讲,为什么动态多态和虚继承都使用 virtual关键字来表示?

virtual的解释
1. Existing or resulting in essence or effect though not in actual fact, form, or name.
实质上的,实际上的:虽然没有实际的事实、形式或名义,但在实际上或效果上存在或产生的;

2. Existing in the mind, especially as a product of the imagination. Used in literary criticism of text.
虚的,内心的:在头脑中存在的,尤指意想的产物。用于文学批评中。

★C++中的virtual关键字采用第一个定义,即被virtual所修饰的事物或现象在 本质上存在的,但是 没有直观的形式表现,无法直接描述或定义,需要通过其他的 间接方式或手段才能够体现出其实际上的效果。
★关键就在于 存在、间接共享这三种特征
     ——虚函数是 存在
     ——虚函数必须要通过一种 间接的运行时(而不是编译时)机制才能够激活(调用)的函数
     —— 共享性表现在 基类会共享被 派生类重载后的虚函数
虚拟继承如何表现:
     —— 存在即表示虚继承体系和 虚基类确实存在
     —— 间接性表现在当访问虚基类的成员时同样也必须通过某种间接机制来完成(通过 虚基表来完成)
     —— 共享性表现在虚基类会在虚继承体系中被共享,而不会出现多份拷贝


virtual(虚拟继承):

★虚继承:在继承定义中包含了virtual关键字的继承关系
★虚基类:在虚继承体系中的通过virtual继承而来的基类
语法:
class Subclass: public virtual Baseclass
{
       public:    //...
       private:  //...
       protected: //...
};
其中Baseclass称之为Subclass的虚基类;
而不是说Baseclass就是虚基类



虚基派生的构造函数和析构函数:

★对 普通的多层继承而言,构造函数的调用是嵌套的,如由C1类派生C2类,C2类又派生C3类时,C1->C2->C3,有:
          C2(总参数表):C1(参数表)
           C3(总参数表):C2(参数表)
★而对图10-6所示的 虚基派生来说,如果按照上述规则,应该有:
        B(总参数表):A(参数表)
          C(总参数表):A(参数表)
          D(总参数表):B(参数表),C(参数表)//,A(参数表)
★这样“A(参数表)”将被执行2次,这显然不行。
★实际情况是:
       B(总参数表):A(参数表)
        C(总参数表):A(参数表)
        D(总参数表):B(参数表),C(参数表), A(参数表)
★根据虚基派生的性质,类D中只有一份虚基类A的拷贝,因此A类的构造函数在D类中只能被调用一次。所以,从A类直接派生(B和C)和间接派生(D)的类中, 其构造函数的初始化列表中都要列出对虚基类A构造函数的调用。这种机制保证了不管有多少层继承,虚 基类的构造函数必须且只能被调用一次
★如果未列出,则表明调用的是虚基类的无参构造函数, 不管初始化列表中次序如何,对虚基类构造函数的调用总是先于普通基类的构造函数。
★如果是在若干类层次中,从 虚基类直接或间接派生出来的 子类的构造函数初始化列表均有对该虚基类构造函数的调用,那么创建一个子类对象的时候只有该子类列出的虚基类的构造函数被调用,其他类列出的将被忽略,这样就保证虚基类的唯一副本只被初始化一次。即 虚基类的构造函数只被执行一次。
★继承机制下析构函数的调用顺序:
     —— 调用派生类的析构函数
     —— 然后调用派生类中成员对象的析构函数
     —— 调用普通基类的析构函数
     —— 最后调用虚基类的析构函数



小结:
★多态性是面向对象程序设计的又一重要特征,C++中, 多态性是通过虚函数实现的。通过虚函数,可以用同一个指针(尤其是指向基类的指针)访问不同对象的成员函数。 多态配合类型适应,可以为类层次中的函数调用提供统一接口,具有十分重要的意义。
★首先介绍了 静态联编动态联编的含义,进一步引出了虚函数的定义方式, 不同方式的访问,虚函数的响应形式有所不同。在某些情况下,在基类中可能无法定义虚函数,这时可以将其设置为 纯虚函数,此时的类称为 抽象类。纯虚函数和抽象类只能提供接口的作用,抽象类无法创建对象。
★和普通函数一样,多基派生时,虚拟函数也会带来 二义性问题,这在类设计时要合理规划,避免出现编译器无法判断的情况。站在整个类层次的角度来看,其中的同名成员函数存在3种关系: 重载(overload)、覆盖(override)和隐藏(hide、oversee),理解同名函数间的关系有助于代码的阅读和书写,提高程序设计的效率。



转载于:https://www.cnblogs.com/meihao1203/p/9368263.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值