`

虚继承入门

    博客分类:
  • C++
阅读更多
这次失业之后,突然发现现在工作好像真的不是很好找,没办法,主动权不在自己手里,静下心来想想就当通过笔试来给自己查漏补缺吧,昨天笔试遇到一个虚拟继承的概念,这不虽说2分的题,但是这个玩意有大内容,我学习了下,也就先整个入门出来吧:



为什么要引入虚拟继承?

虚拟继承在一般的应用中很少用到,所以也往往被忽视,这也主要是因为在C++中,多重继承是不推荐的,也并不常用,而一旦离开了多重继承,虚拟继承就完全失去了存在的必要(因为这样只会降低效率和占用更多的空间,关于这一点,我自己还没有太多深刻的理解,有兴趣的可以看网络上白杨的作品《RTTI、虚函数和虚基类的开销分析及使用指导》,说实话我目前还没看得很明白,高人可以指点下我)。

以下面的一个例子为例:

#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、重载函数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 : virtual public CA  //也有一种写法是class CB : public virtual CA

{                       //实际上这两种方法都可以

};



class CC : virtual public 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));



另注:

如果CB,CC中各定义一个int型变量,则sizeof(CD)就变成20(两个vbptr + 3个sizoef(int)

如果CA中添加一个virtual void f1(){},sizeof(CD) = 16(两个vbptr + sizoef(int)+vptr);

再添加virtual void f2(){},sizeof(CD) = 16不变。原因如下所示:带有虚函数的类,其内存布局上包含一个指向虚函数列表的指针(vptr),这跟有几个虚函数无关。

以上内容涉及到类对象内存布局问题,本人还难以做过多展开,先贴这么多,本篇文章只是考虑对于虚拟继承进行入门,至于效率、应用等未作展开。本文在网上文章基础上修改了下而得此篇,原文载于http://blog.csdn.net/billdavid/archive/2004/06/23/24317.aspx

另外关于虚继承和虚基类的讨论,博客园有篇文章《虚继承与虚基类的本质》,总结得更为详细一点。
分享到:
评论

相关推荐

    Visual C++ 2005入门经典中文版--第09章 类继承和虚函数

    Visual C++ 2005入门经典中文版,第09章 类继承和虚函数

    C++入门基础_30分钟入门教程

    C++的多态包括函数重载、虚函数、运算符重载等。 1.2 开发工具 为了充分利用C++,使用集成开发环境(IDE)至关重要。常见的C++ IDE有C++ Builder、Code::Blocks、Eclipse CDT等。本教程将重点介绍如何使用Visual ...

    C++入门指南-v2.4.pdf

    4.8 虚继承和虚基类 88 五、C++多态与抽象类 91 5.1 多态概念介绍 91 5.2 虚函数 92 5.3 纯虚函数和抽象类 95 六、C++运算符重载 97 6.1 运算符重载语法介绍 97 6.2 可重载运算符与不可重载运算符 98 6.3 一元运算符...

    Visual C++ 2005 入门经典 09- 类继承和虚函数

    Visual C++ 2005 入门经典 (美) Ivor Horton 著 李颂华 康会光 译

    C++快速入门经典(很不错的)

    继承允许子类从父类继承属性和方法,有三种继承类型:公有、私有和保护,还可以进行虚继承以优化内存使用;多态体现在函数重载、覆盖、虚函数、运算符重载和抽象类等。 4. **开发工具** 集成开发环境(IDE)是提高...

    C++快速入门课件全解

    特别是虚函数和纯虚函数在多态中的作用。 5. **模板**:模板是C++中的通用编程工具,允许你创建泛型函数和泛型类,实现代码复用,减少冗余。 6. **异常处理**:C++提供了异常处理机制,用于处理程序运行时可能出现...

    C#从入门到精通 第3版 原书配套光盘资源下载

    C#通过接口和虚方法支持多态。 ### 4. 进阶主题 - **泛型编程**: - 泛型允许编写可重用的类、接口和方法,这些组件可以工作在多种数据类型上。 - **LINQ (Language Integrated Query)**: - LINQ提供了一种简单...

    C语言入门到高级实例源码

    包含目录: C语言数据类型及输入输出...虚继承及其它特性,zip 虚函数与抽象类.zip 命名空间与模板.zip C++I0流类库.zip STL(vector deque stack).zip STL(queue set map).zip C港嬌芤璇硙驟Ⅺ聪産走冁闭异常处理.zip

    C# 控制台入门 修饰符 构造函数 虚方法 静态字段 接口 抽象类 循环 适合入门

    一个简短的控制台程序,使用了构造函数,虚方法 静态类,静态字段,接口,抽象类,继承,适合刚入门的人看

    《Visual C++ 2010入门经典》文字版[PDF]

    - **第9章:类的继承与虚函数**:探讨面向对象编程中重要的继承机制和虚函数的使用。 - **第10章:标准模板库(STL)**:介绍STL的基础知识,包括容器、算法和迭代器。 - **第11章:调试技术**:提供实用的调试技巧...

    鸡啄米:C++编程入门系列

    鸡啄米:C++编程入门系列之四十二(继承与派生:虚基类及其派生类 的构造函数) 鸡啄米:C++编程入门系列之四十三(继承与派生:赋值兼容规则) 第八部分:多态性 鸡啄米:C++编程入门系列之四十四(多态性:...

    C++快速入门教程

    多态则是通过虚函数实现的,它允许基类的指针或引用调用派生类的重写方法。 C++标准库也是学习的重要部分,它包含了各种容器(如vector、list、set等)、算法(如排序、查找等)和输入/输出流(如iostream用于处理...

    C++入门经典源代码

    C++的继承机制允许一个类(子类)继承另一个类(父类)的特性,实现代码复用。多态性是通过虚函数和接口实现的,允许不同的对象对同一消息作出不同的响应。 C++还包括模板和STL(Standard Template Library,标准...

    Visual C++ 2013入门经典_高清版

    多态则是通过虚函数和抽象类来实现的,它使得不同的对象可以对同一条消息做出不同的响应。 在深入讲解了C++的基础和面向对象特性后,书籍会引导读者熟悉Visual Studio 2013开发环境。这包括创建项目、设置编译选项...

    C++从入门到精通(第4版) PPT电子课件( 可供教学参考).7z

    虚函数和纯虚函数是实现多态的重要工具。 此外,C++还包含STL(标准模板库),它是C++编程的一大利器。STL提供了容器(如vector、list、set等)、迭代器、算法和函数对象等组件,极大地提高了开发效率。例如,通过...

    C++入门课件

    课件会涵盖如何声明和使用派生类,以及虚函数和纯虚函数的概念。 模板是C++中的一种通用编程工具,可以创建泛型函数和泛型类,以处理不同数据类型。课件会介绍模板函数和模板类的使用方法,以及模板特化和模板元...

    C++入门经典 第三版 习题答案

    )、继承(如class Student : public Person)、封装(隐藏实现细节)、多态(通过虚函数实现)等概念。通过习题,学生可以学会如何设计和实现这些面向对象特性。 在解答过程中,学生还可以接触到标准库的使用,...

Global site tag (gtag.js) - Google Analytics