虚拟继承在一般的应用中很少用到,所以也往往被忽视,这也主要是因为在C++中,多重继承是不推荐的,而一旦离开了多重继承,虚拟继承就完全失去了存在的必要
(因为这样只会降低效率和占用更多的空间,实在是一无是处)。
以下面的一个例子为例:
#include <iostream.h>
#include <memory.h>
class CA
{
int k; //为了便于说明后面的内存结构特别添加
public:
void f() {cout << "CA::f" << endl;}
};
class CB : public CA
{
};
class CC : public CA
{
};
class CD : public CB, public CC
{
};
void main()
{
CD d;
d.f();
}
当编译上述代码时,我们会收到如下的错误提示:
error C2385: 'CD::f' is ambiguous
即编译器无法确定你在d.f()中要调用的函数f到底是哪一个。这里可能会让人觉得有些奇怪,命名只定义了一个CA::f,既然大家都派生自CA,那自然就是调用的CA::f,为什么还无法确定呢?
这是因为编译器在进行编译的时候,需要确定子类的函数定义,如CA::f是确定的,那么在编译CB、CC时还需要在编译器的语法树中生成CB::f,CC::f等标识,那么,在编译CD的时候,由于CB、CC都有一个函数f,此时,编译器将试图生成两个CD::f标识,显然这时就要报错了。(当我们不使用CD::f的时候,以上标识都不会生成,所以,如果去掉d.f()一句,程序将顺利通过编译)
要解决这个问题,有两个方法:
1、CD重载函数f():此时由于我们明确定义了CD::f,编译器检查到CD::f()调用时就无需再像上面一样去逐级生成CD::f标识了;
此时CD的元素结构如下:
--------
|CB(CA)|
|CC(CA)|
--------
故此时的sizeof(CD) = 8;(CB、CC各有一个元素k)
2、使用虚拟继承:虚拟继承又称作共享继承,这种共享其实也是编译期间实现的,当使用虚拟继承时,上面的程序将变成下面的形式:
#include <iostream.h>
#include <memory.h>
class CA
{
int k;
public:
void f() {cout << "CA::f" << endl;}
};
class CB :virtualpublic CA
{
};
class CC :virtualpublic CA
{
};
class CD : public CB, public CC
{
};
void main()
{
CD d;
d.f();
}
此时,当编译器确定d.f()调用的具体含义时,将生成如下的CD结构:
----
|CB|
|CC|
|CA|
----
同时,在CB、CC中都分别包含了一个指向CA的vbptr(virtual base table pointer),其中记录的是从CB、CC的元素到CA的元素之间的偏移量。此时,不会生成各子类的函数f标识,除非子类重载了该函数,从而达到“共享”的目的。
也正因此,此时的sizeof(CD) = 12(两个vbptr + sizoef(int));
所有这一切都是编译期间决定的,只是编译器为了提供这样一个新的语法功能为我们多作了一些事情而已。
注:以上讨论限MS Visual C++编译器。
分享到:
相关推荐
c++虚拟继承的一个典型例子,通过这个例子可以让初学者从根本体会到虚拟继承是怎么回事
关于虚拟目录继承根Web.Config的问题解决办法
1。多继承 基类 派生类(还要有多个父类) 第二条:涉及构造和析构 ... 水平方向上:体现出继承顺序 先虚拟继承 再普通继承 通过实例化类 体现对象构造和析构的顺序 还要有函数重载 指针 指针悬挂 无参函数等问题....
仅仅是一个讨论使用的样例程序,详细内容参考:http://blog.csdn.net/magictong/article/details/22202393
1.为什么要引入虚拟继承虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、...
而继承包含了虚拟继承和普通继承,在可见性上分为public、protected、private。可见性继承比较简单,而虚拟继承对学习c++的难度较大。 首先,虚拟继承与普通继承的区别有: 假设derived 继承自base类,那么...
关于虚拟仪器的一些资料关于虚拟仪器的一些资料关于虚拟仪器的一些资料关于虚拟仪器的一些资料
关于网络虚拟财产的民法思考.pdf
关于虚拟现实技术在高职实训教学中的应用思考.pdf
课程复习题哦,比较详细的,如果你能够把这些都找到弄懂,那包过的!
比如:虚函数必须要通过一种间接的运行时(而不是编译时)机制才能够激活(调用)的函数,而虚继承也是必须在运行时才能够进行定位访问的一种体制。存在,但间接。其中关键在于存在、间接和共享这三种特征。
类的继承与派生 注释详细 虚拟继承,派生对象访问 操作多多
这个虚拟视频,虚拟相机的rom经过了好几年的发展了,市面上出现得比较多的就是 小米四小米4虚拟视频刷机包,小米note虚拟视频刷机包,小米6的虚拟视频刷机包,还有OPPOr9s也有虚拟视频刷机包,oppor9s的话也有6键...
虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱虚拟光驱...
关于虚拟桌面的开发.pdf
下载于维基的收费论文,拿出来免费共享。主要讲述了角色继承的实现方法
本文简单介绍多态和多重继承、虚拟继承的基本概念。随后重点分析了C++中对象模型之间的差异和运行效率
虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕虚拟屏幕...