当前位置: 首页 > news >正文

C++中的虚继承

在 C++ 里,虚继承是一种特殊的继承方式,其主要作用是解决多重继承时出现的菱形(diamond问题)继承问题,防止数据冗余和歧义。

通过一个例子来说明:

#include <iostream>
using namespace std;class A {
public:int data;
};class B : public A {};
class C : public A {};
class D : public B, public C {};int main() {D d;d.B::data = 1;  // 必须明确指定作用域,不然会产生歧义d.C::data = 2;cout << d.B::data << " " << d.C::data << endl;return 0;
}

这里类的继承关系如下:

D->B->A

   ->C->A

这里如果要对data赋值,必须要指明是哪个继承类的成员。如果要解决上述问题,可让类 B 和类 C 虚继承类 A,这样类 D 就只会包含一份类 A 的数据。示例如下:

#include <iostream>
using namespace std;class A {
public:int data;
};class B : virtual public A {};  // 虚继承
class C : virtual public A {};  // 虚继承
class D : public B, public C {};int main() {D d;d.data = 1;  // 不会有歧义cout << d.data << endl;  // 输出:1return 0;
}

起实现原理是:

  • 当使用虚继承时,派生类会包含一个虚基类指针(vbptr)或者虚基类表,借助它们来定位虚基类的位置。
  • 不管继承路径有多少条,虚基类的数据成员在内存中都只会存在一份。

在虚继承的情况下,虚基类的构造函数由最底层的派生类(如类 D)负责调用,中间层的派生类(如类 B 和类 C)不会调用虚基类的构造函数。例如:

#include <iostream>
using namespace std;class A {
public:A(int val) : data(val) { cout << "A constructor, val is " << val << endl; }A() { data = 6; cout << "A default constructor, data is " << data << endl;}int data;
};class B : virtual public A {
public:B() : A(1) { cout << "B constructor" << endl; }  // 不会调用A的构造函数
};class C : virtual public A {
public:C() : A(2) { cout << "C constructor" << endl; }  // 不会调用A的构造函数
};class D : public B, public C {
public:D() : A(3) { cout << "D constructor" << endl; }  // 直接调用A的构造函数
};int main() {D d;return 0;
}

执行结果如下:

A constructor, val is 3
B constructor
C constructor
D constructor

而如果D不调用A的构造函数,则会调用A的默认构造函数,例:

#include <iostream>
using namespace std;class A {
public:A(int val) : data(val) { cout << "A constructor, val is " << val << endl; }A() { data = 6; cout << "A default constructor, data is " << data << endl;}int data;
};class B : virtual public A {
public:B() : A(1) { cout << "B constructor" << endl; }  // 不会调用A的构造函数
};class C : virtual public A {
public:C() : A(2) { cout << "C constructor" << endl; }  // 不会调用A的构造函数
};class D : public B, public C {
public:D() { cout << "D constructor" << endl; }  // 直接调用A的构造函数
};int main() {D d;return 0;
}

结果如下:

A default constructor, data is 6
B constructor
C constructor
D constructor

http://www.dtcms.com/a/288123.html

相关文章:

  • 思维链(CoT)技术全景:原理、实现与前沿应用深度解析
  • Edge浏览器设置网页自动翻译
  • 从随机数值到特征检测器的学习与更新
  • [硬件电路-37]:模拟电路、数字电路与计算软件信号处理的全方位比较
  • 暑假--作业3
  • 物联网系统中的可视化大屏定义
  • VSCode - VSCode 查找中文字符
  • 『 C++ 入门到放弃 』- AVL树
  • OpenCV 官翻 1 -介绍、安装、功能概览、核心操作
  • Streamlit 官翻 5 - 部署、社区云 Deploy
  • Linux内核空间的布局
  • 前端面试专栏-工程化:26.性能优化方案(加载优化、渲染优化)
  • 《Qt5串口开发》搭建跨平台通信系统
  • “外卖大战”正在改变国内“大零售”
  • 数据增强和微调
  • Codeforces Round 1037 (Div. 3)
  • windows docker-02-docker 最常用的命令汇总
  • uniapp props、$ref、$emit、$parent、$child、$on
  • 【数据结构】栈(stack)
  • xss-labs1-8题
  • ubuntu24 ros2 jazzy
  • OpenVINO使用教程--图像增强算法DarkIR
  • 华为擎云L420安装LocalSend
  • Oracle为什么需要临时表?——让数据处理更灵活
  • LeetCode 322. 零钱兑换 LeetCode 279.完全平方数 LeetCode 139.单词拆分 多重背包基础 56. 携带矿石资源
  • 【补题】Codeforces Round 958 (Div. 2) D. The Omnipotent Monster Killer
  • 窗口(6)-QMessageBox
  • ctf.show-web习题-web4-flag获取详解、总结
  • 动态规划——状压DP经典题目
  • Weavefox 图片 1 比 1 生成前端源代码