现代c++2.4 虚继承

为了让你更直观地理解,我们将其分解为"为什么需要它"、"怎么使用"以及图片中提到的"一个巧妙的设计"三个部分来讲解。

一、 为什么需要它?(解决什么问题?)

在 C++11 之前,如果你的派生类(子类)需要完全保留基类(父类)的所有构造函数,你必须在派生类中逐一手动重写(转发)这些构造函数。

举例说明(C++11 之前的痛苦):

假设基类 Base 有多个构造函数:

class Base {

public:

Base() { cout << "Base 默认构造" << endl; }

Base(int a) { cout << "Base 构造,a = " << a << endl; }

Base(double b) { cout << "Base 构造,b = " << b << endl; }

};

如果在 C++11 之前,你想让派生类 Derived 也拥有这些构造函数,你必须这样写:

class Derived : public Base {

public:

Derived() : Base() {} // 必须手动写

Derived(int a) : Base(a) {} // 必须手动写

Derived(double b) : Base(b) {} // 必须手动写

};

缺点:如果基类的构造函数很多,或者基类修改了构造函数,派生类也必须跟着修改,不仅代码冗余,而且极易出错,维护成本极高。

二、 C++11 的解决方案:using Base::Base;

C++11 标准引入了语法 using 基类名::基类名;。有了它,上述代码只需要一行:

class Derived : public Base {

public:

using Base::Base; // 这一行就把基类的所有构造函数都"继承"过来了!

};

效果:Derived 类现在自动拥有了 Base 的所有构造函数。你可以像这样使用它们:

Derived d1; // 调用 Base()

Derived d2(10); // 调用 Base(int)

Derived d3(3.14); // 调用 Base(double)

三、 图片中提到的"巧妙之处":隐式声明与惰性生成

图片中有一句很重要的话:

"继承构造函数与类的一些默认函数(默认构造、析构、拷贝构造函数等)一样,是隐式声明,如果一个继承构造函数不被相关代码使用,编译器不会为其产生真正的函数代码。"

这其实包含两个核心概念:

  1. 什么是"隐式声明"?

    当你写下 using Base::Base; 时,并没有真正把基类的构造函数代码拷贝或复制到子类中。编译器只是在后台默默地"声明"了这些构造函数存在于子类中。这和编译器自动给你的类生成的"默认构造函数"、"析构函数"是一样的,都是编译器在后台帮你声明的。

  2. 什么是"惰性生成"(不产生真正的函数代码)?

    为了优化编译速度和生成的可执行文件大小,现代编译器都有一个特性:如果你声明了一个函数但从未调用它,编译器就不会为它生成真正的机器码(汇编指令)。

举例:

class Base {

public:

Base(int a, int b) { /* 一些复杂的初始化代码 */ }

};

class Derived : public Base {

public:

using Base::Base; // 声明继承了 Base(int, int)

};

int main() {

Derived d(1, 2); // 只有在这里真正使用时,编译器才会去生成 Derived(int, int) 的底层代码

return 0;

}

如果你只写了 using Base::Base;,但在 main 函数里根本没用到 Derived(int, int) 这个构造函数,编译器就会直接无视它,不会生成任何对应的机器指令。这就避免了代码膨胀,提高了程序的运行效率。

总结

  • 核心作用:省去在派生类中大量重复手写基类构造函数的麻烦。
  • 语法:在派生类的 public 部分写上 using 基类名::基类名;。
  • 性能优势:它是按需生成的(惰性生成),没用到的构造函数不会占用最终程序的空间。

需要我用具体的代码为你演示一下 using 继承时,如果基类和子类构造函数参数冲突了该如何处理吗?

相关推荐
1024奇点6 小时前
【仓颉语言入门 · 第二篇 第 22 课】
开发语言·ide·开源
Warren2Lynch7 小时前
C4 模型详解:利用 Visual Paradigm 可视化软件架构的综合指南
开发语言·uml
天河归来7 小时前
第三方接口不稳定,如何让核心任务继续完成
java·大数据
FlightYe7 小时前
视界原理之3D视频(四):裸眼、眼镜和头显
android·linux·c++·3d·ffmpeg·音视频
Knight_AL7 小时前
Java 文件下载时文件名中的 `#` 被转换成 `%23`?一次 URL 编码与解码问题排查
java·开发语言
FRing038 小时前
vue2干货总结2(v-bind、v-for、v-model、指令修饰符、v-bind操作class和style)
开发语言·前端·vue.js·vue2
by209999 小时前
C++ 智能指针的所有权与使用
开发语言·c++·经验分享
砚底藏山河9 小时前
python量化自定义周期 K 线合成
java·开发语言·数据库·python·金融
IT召唤狮9 小时前
开源企业级零信任项目Pangolin,零信任能挡住PHP核弹漏洞吗?
开发语言·开源·php
知已难寻9 小时前
03 · OpenStack的计算管理 Nova
运维·服务器·开发语言·云原生·云计算·openstack·开源软件