当前课程知识点:C++语言程序设计进阶 >  第七章 继承与派生 >  派生类成员的标识与访问 >  虚基类

返回《C++语言程序设计进阶》慕课在线视频课程列表

虚基类在线视频

虚基类

虚基类

例7-8 虚基类举例

virtual-base.png

#include <iostream>
using namespace std;
class Base0 {
public:
    int var0;
    void fun0() { cout << "Member of Base0" << endl; }
};
class Base1: virtual public Base0 {
public: 
    int var1;
};
class Base2: virtual public Base0 {
public: 
    int var2;
};


class Derived: public Base1, public Base2 {
//定义派生类Derived 
public: 
    int var;
    void fun() {
        cout << "Member of Derived" << endl;
    }
};

int main() {    
    Derived d;
    d.var0 = 2; //直接访问虚基类的数据成员
    d.fun0();     //直接访问虚基类的函数成员
    return 0;
}

虚基类及其派生类构造函数

有虚基类时的构造函数举例(补7-4)

#include <iostream>
using namespace std;

class Base0 {   
public:
    Base0(int var) : var0(var) { }
    int var0;
    void fun0() { cout << "Member of Base0" << endl; }
};
class Base1: virtual public Base0 {
public: 
    Base1(int var) : Base0(var) { }
    int var1;
};
class Base2: virtual public Base0 { 
public:
    Base2(int var) : Base0(var) { }
    int var2;
};

class Derived: public Base1, public Base2 {
public:
    Derived(int var) : Base0(var), Base1(var), Base2(var) 
   { }
    int var;
    void fun() 
   { cout << "Member of Derived" << endl; }
};

int main() {    //程序主函数
    Derived d(1);
    d.var0 = 2; //直接访问虚基类的数据成员
    d.fun0();   //直接访问虚基类的函数成员
    return 0;
}



下一节:小结

返回《C++语言程序设计进阶》慕课在线视频列表

虚基类课程教案、知识点、字幕

大家好

欢迎回来继续学习

C++语言程序设计

这一节我们来学习虚基类

虚基类是什么

为什么我们需要虚基类

现在我们考虑这样一个问题

是不是说

我们继承多个基类的时候

它们有重名的成员都没有关系

我们访问的时候呢

用类名限定就可以了

问题是不是就这么简单呢

大家有没有想过

如果某个派生类的多个基类

实际上呢

又曾经派生自

一个共同的最远基类的情况

这种情况下

这些基类里面

就会有同名的成员

不仅名字相同

它本质上就是相同的东西

最后到最远派生类中

又汇聚到一起了

这个时候带来的麻烦

好象不仅仅是说

区分一下名字

避免二异性的问题吧

对 这个时候麻烦会更多一些

我们就来看到底有什么麻烦

怎么解决这个麻烦

我们需要解决的问题

简单来讲就是

当派生类从多个基类派生

而这些基类

又有共同基类

那么这种情况下

我们要访问那些

从这个最远的共同基类中

继承过来的成员的时候

不仅仅是有二异性的问题

实际上它是产生了冗余

而这个冗余

不仅仅是浪费了存储空间的问题

很有可能会带来不一致性

那么怎么解决这个问题呢

在C++中

有虚基类这种语法机制

某种程度上可以解决这个问题

这个时候呢

就需要我们在继承基类的时候

用这个virtual关键字

说明这是一个虚继承

这种虚继承的作用呢

主要是用来解决多继承的时候

可能发生的对同一个基类

继承多次而产生的这种二异性

和冗余的问题

用了虚基类这种机制

就可以为最远派生类

提供唯一的基类成员

而不产生重复的多次复制

那这里要注意的就是说

要在

一定要在第一级继承的时候

就要将共同基类设计为虚基类

下面呢

我通过例子和图

给大家解释一下

大家就比较清楚了

这到底意味着什么

那避免二异性和冗余呢

我们可以采用虚基类

比如说

我们可以将Base0类

作为它直接派生类

Base1 Base2的虚基类

也就是说Base1虚继承Base0

Base2虚继承Base0

那么Derived

再继承Base1 Base2

这样呢

它最终的结果就是什么呢

在Derived对象里面

不会存在Base0类的双份的成员

那么看起来

它也是包含着

从Base1继承的成员

和从Base2继承的成员

但是从Base1继承的Base0成员

实际上这个地方放了一个指针

指向真正的Base0成员

Base2的也是

所以呢

实质上从最远的基类

继承过来的成员

在最远派生类中只有一份

我们看这个程序

我们只要在

Base1继承Base0的时候

加一个virtual

在Base2继承Base0的时候

也加一个virtual

在第一级继承的时候

就作为虚继承

然后呢

这种二异性和冗余的问题呢

在这个例题中就这样解决了

我们知道了虚基类

可以在某种程度上

解决这个二异性和冗余的问题

但是

虚基类也给我们带来了

另外一个方面的麻烦

就是这个派生类的构造函数

怎么写

我们将建立对象的时候

所指定的这个类型

称为最远派生类

它是目前最远的这一级

对吧

那么虚基类的成员呢

应该是由最远派生类的构造函数

通过调用虚基类的构造函数

进行初始化的

那么这个原则

就跟我们以前学的语法

不太一样了

以前我们是说

每个派生类

只负责给它的直接基类构造函数

传递参数

但是现在

这个最远派生类除此而外

还要给那个最远的

最顶上的那个基类

它的构造函数传递参数

就是那个虚基类

那么在整个继承结构中呢

实际上直接或间接

继承虚基类的所有派生类

都必须在构造函数的初始化

列表中

为虚基类的构造函数列出参数

如果说你没有列出

那就表示要调用

这个虚基类的默认构造函数了

可是这么多级的派生类

都给它传参数

用哪个呀

在构造对象的时候呢

只有最远派生类的构造函数

会真的去调用虚基类的构造函数

而其他类

对虚基类构造函数的调用呢

就都被忽略了

也就是中间各级传的参数

就都被忽略了

只收那个最远派生类

传给虚基类的参数

下面呢

我们通过一个例子来演示

有虚基类的时候

这个最远派生类的构造函数

该怎么写

有虚基类的时候呢

每一级的派生类

都要给最远的那个基类

负责传递参数

我们看

那么构造函数怎么写呢

直接的派生类Base1

当然它依然是给

它的直接基类构造函数

Base0传递参数

Base2也是

它是Base0的直接派生类

它也要给它的构造函数

传递参数

那我们来看

下级派生类Derived

如果不是虚继承的话

它是只要给自己的直接基类

构造函数传递参数就行了

现在由于我们使用了虚继承

所以Derived类

它的构造函数

还要负责给最远基类

传递参数

也要给Base0类传递参数

那么当构造

Derived类对象的时候

Base0的构造函数被调用几次呢

当然只被调用一次

只有这个最远派生类

传递这个参数被接收

用来调用Base0的构造函数

那么在中间的地方

其他的这些Base1 Base2

传递的参数呢

就都被忽略了

所以大家不用担心说

大家都给最远基类传参数

它的构造函数

会不会不知道接收哪个参数

会不会被调用执行多次啊

不会的

只有这个最远派生类对象

构造的时候

传的这个参数是起作用的

C++语言程序设计进阶课程列表:

第七章 继承与派生

-导学

--导学

-继承的基本概念和语法

--继承的基本概念和语法

-第七章 继承与派生--继承的基本概念和语法习题

-继承方式

--继承方式简介及公有继承

--私有继承和保护继承

-第七章 继承与派生--继承方式

-基类与派生类类型转换

--基类与派生类类型转换

-第七章 继承与派生--基类与派生类类型转换

-派生类的构造和析构

--派生类的构造函数

--派生类的构造函数举例

--派生类的复制构造函数

--派生类的析构函数

--第七章 继承与派生--派生类的构造和析构

-派生类成员的标识与访问

--访问从基类继承的成员

--虚基类

-第七章 继承与派生--派生类成员的标识与访问

-小结

--小结

-综合实例

--第七章综合实例

-实验七

--实验七

-第七章讲义

第八章 多态性

-导学

--导学

-第八章 多态性--导学

-运算符重载

--运算符重载的规则

--双目运算符重载为成员函数

--单目运算符重载为成员函数

--运算符重载为非成员函数

-第八章 多态性--运算符重载

-虚函数

--虚函数

--虚析构函数

--虚表与动态绑定

-第八章 多态性--虚函数

-抽象类

--抽象类

--第八章 多态性--抽象类

-override与final

--override与final

-第八章 多态性--override与final

-小结

--第八章小结

-综合实例

--第八章综合实例

-实验八

--实验八

- 第八章讲义

第九章 模板与群体数据

-导学

--导学

-模板

--函数模板

--类模板

-第九章 模板与群体数据--模板

-线性群体

--线性群体的概念

-第九章 模板与群体数据--线性群体

-数组

--数组类模板

--例9-4数组类应用举例

-链表

--链表的概念与结点类模板

--链表类模板

-第九章 模板与群体数据--链表

-栈

--栈类模板

--栈类模板课后习题

--例9-9 栈的应用

--例9-9 栈的应用课后习题

-队列

--队列类模板

-第九章 模板与群体数据--队列

-排序

--排序概述

--插入排序

--选择排序

--交换排序

-第九章 模板与群体数据--排序

-查找

--查找

--查找课后习题

-小结

--小结

-综合实例

--综合实例

-实验九

--实验九

- 第九章讲义

第十章 泛型程序设计与C++标准模板库

-导学

--导学

-泛型程序设计及STL的结构

--泛型程序设计的基本概念

--STL简介

-第十章 泛型程序设计与C++标准模板库--泛型程序设计及STL的结构

-迭代器

--迭代器

-第十章 泛型程序设计与C++标准模板库--迭代器

-容器的基本功能与分类

--容器的基本功能与分类

-第十章 泛型程序设计与C++标准模板库--容器的基本功能与分类

-顺序容器

--顺序容器的基本功能

--顺序容器的特征

--顺序容器的插入迭代器与适配器

--第十章 泛型程序设计与C++标准模板库--顺序容器

-关联容器

--关联容器分类和基本功能

--集合

--映射

--多重集合和多重映射

-第十章 泛型程序设计与C++标准模板库--关联容器

-函数对象

--函数对象

--函数适配器

-算法

--算法

-小结

--第十章小结

-综合实例

--综合实例

-实验十

--实验十

- 第十章讲义

第十一章 流类库与输入/输出

-导学

--导学

-I/O流的概念及流类库结构

--I/O流的概念及流类库结构

-第十一章 流类库与输入/输出--I/O流的概念及流类库结构

-输出流

--输出流概述

--向文本文件输出

--向二进制文件输出

--向字符串输出

-第十一章 流类库与输入/输出--输出流

-输入流

--输入流概述

--输入流应用举例

--从字符串输入

-第十一章 流类库与输入/输出--输入流

-输入/输出流

--输入/输出流

-第十一章 流类库与输入/输出--输入/输出流

-小结

--小结

-综合实例

--综合实例

-实验十一

--实验十一

- 第十一章讲义

第十二章 异常处理

-导学

--第12章导学

-异常处理的思想与程序实现

--异常处理的思想与程序实现

-第十二章 异常处理--异常处理的思想与程序实现

-异常处理中的构造与析构

--异常处理中的构造与析构

-第十二章 异常处理--异常处理中的构造与析构

-标准程序库异常处理

--标准程序库异常处理

-第十二章 异常处理--标准程序库异常处理

-小结

--第12章小结

-综合实例

--综合实例

-实验十二

--实验十二

- 第十二章讲义

虚基类笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。