首页 > 其他分享 >虚基类详解-转

虚基类详解-转

时间:2022-11-25 12:44:42浏览次数:38  
标签:初始化 int 基类 详解 派生类 public 构造函数

https://www.cnblogs.com/sunbines/p/9215687.html

虚基类

一、虚基类介绍

多继承时很容易产生命名冲突,即使我们很小心地将所有类中的成员变量和成员函数都命名为不同的名字,命名冲突依然有可能发生,比如非常经典的菱形继承层次。如下图所示:

                                                                                         

类A派生出类B和类C,类D继承自类B和类C,这个时候类A中的成员变量和成员函数继承到类D中变成了两份,一份来自 A-->B-->D 这一路,另一份来自 A-->C-->D 这一条路。

在一个派生类中保留间接基类的多份同名成员,虽然可以在不同的成员变量中分别存放不同的数据,但大多数情况下这是多余的:因为保留多份成员变量不仅占用较多的存储空间,还容易产生命名冲突,而且很少有这样的需求。

为了解决这个问题,C++提供了虚基类,使得在派生类中只保留间接基类的一份成员。

声明虚基类只需要在继承方式前面加上 virtual 关键字,请看下面的例子:

 

复制代码
 1 #include <iostream>
 2 using namespace std;
 3 
 4 class A {
 5 protected:
 6     int a;
 7 public:
 8     A(int a) : a(a) {}
 9 };
10 
11 class B : virtual public A {
12 protected:
13     int b;
14 public:
15     B(int a, int b) : A(a), b(b) {}
16 };
17 
18 class C : virtual public A {
19 protected:
20     int c;
21 public:
22     C(int a, int c) : A(a), c(c) {}
23 };
24 
25 class D : virtual public B, virtual public C {
26 private:
27     int d;
28 public:
29     D(int a, int b, int c, int d) : A(a), B(a, b), C(a, c), d(d) {}
30     void display();
31 };
32 
33 void D::display()
34 {
35     cout << "a = " << a << endl;
36     cout << "b = " << b << endl;
37     cout << "c = " << c << endl;
38     cout << "d = " << d << endl;
39 }
40 
41 int main()
42 {
43     (new D(1, 2, 3, 4))->display();
44     return 0;
45 }
复制代码

输出结果:

本例中我们使用了虚基类,在派生类D中只有一份成员变量 a 的拷贝,所以在 display() 函数中可以直接访问 a,而不用加类名和域解析符。

请注意派生类D的构造函数,与以往的用法有所不同。以往,在派生类的构造函数中只需负责对其直接基类初始化,再由其直接基类负责对间接基类初始化。现在,由于虚基类在派生类中只有一份成员变量,所以对这份成员变量的初始化必须由派生类直接给出。如果不由最后的派生类直接对虚基类初始化,而由虚基类的直接派生类(如类B和类C)对虚基类初始化,就有可能由于在类B和类C的构造函数中对虚基类给出不同的初始化参数而产生矛盾。所以规定:在最后的派生类中不仅要负责对其直接基类进行初始化,还要负责对虚基类初始化。

 

有的读者会提出:类D的构造函数通过初始化表调了虚基类的构造函数A,而类B和类C的构造函数也通过初始化表调用了虚基类的构造函数A,这样虚基类的构造函数岂非被调用了3次?大家不必过虑,C++编译系统只执行最后的派生类对虚基类的构造函数的调用,而忽略虚基类的其他派生类(如类B和类C)对虚基类的构造函数的调用,这就保证了虚基类的数据成员不会被多次初始化。

 

最后请注意:为了保证虚基类在派生类中只继承一次,应当在该基类的所有直接派生类中声明为虚基类,否则仍然会出现对基类的多次继承。

 

标签:初始化,int,基类,详解,派生类,public,构造函数
From: https://www.cnblogs.com/ysgd/p/16924759.html

相关文章

  • PHP字符逃逸导致的对象注入详解
    产生原因:序列化的字符串在经过过滤函数不正确的处理而导致对象注入,目前看到都是因为过滤函数放在了serialize函数之后,要是放在序列化之前应该就不会产生这个问题<?phpfuncti......
  • Pod控制器详解(Job)
    JobJob,主要用于负责批量处理(一次要处理指定数量任务)短暂的一次性(每个任务仅运行一次就结束)任务。Job特点如下:当Job创建的pod执行成功结束时,Job将记录成功结束的pod......
  • 【 Makefile 编程基础之四】详解Makefile 函数的语法与使用!
    本站文章均为​​ 李华明Himi ​​​原创,转载务必在明显处注明使用函数:在Makefile中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能。make所支持......
  • 【 Makefile 编程基础之三】详解 Makefile 变量的定义规则使用!
    本站文章均为​​ 李华明Himi ​​​原创,转载务必在明显处注明:使用变量:在Makefile中的定义的变量,就像是C/C++语言中的宏一样,他代表了一个文本字串,在Makefile中执行的时候......
  • 代码案例详解!如何让机器学习模型自解释!⛵
    ......
  • redis和memcached的区别详解
    redis和memcached的区别详解Redis和Memcache都是基于内存的数据存储系统。Memcached是高性能分布式内存缓存服务;Redis是一个开源的key-value存储系统。与Memcached类似......
  • MySQL进阶实战3,mysql索引详解,上篇
    一、索引索引是存储引擎用于快速查找记录的一种数据结构。我觉得数据库中最重要的知识点,就是索引。存储引擎以不同的方式使用B-Tree索引,性能也各有不同,各有优劣。例如MyI......
  • Django ORM模型一对一、一对多、多对多的操作详解
    一、快速创建项目1、创建项目>>django-adminstartprojecttest03_20181211>>pythonmanage.pystartappapp1 2、配置文件settings.py#1、数据库:(settings.p......
  • 5.OAuth2详解
     理论OAuth是一个关于授权(authorization)的开放网络标准,用来授权第三方应用获取用户数据,是目前最流行的授权机制,它当前的版本是2.0。应用场景假如你正在“网站A”上冲......
  • 操作符详解(day13)
    操作符是直接对内存里存储的值进行操作,而函数是更外层的操作方式。以操作整形变量举例:在内存中,整数都是以补码形式存储的,所以操作符可以直接操纵内存中的补码的值,而printf函......