网站首页 > 博客文章 正文
头条小白,望大家多多关注。跪求关注,你的关注是对我最大的鼓励,关注看下期。
上次在CTAD中,提了一下此特性可以结合C++编译期多态使用,效果更好。那什么是编译期多态呢?
这我们可能要先简单介绍下运行期多态的概念了,运行期多态也是基本所有高级编程语言都支持的特性,类比Rust 中的trait, Java 中的interface, C++ 中的virtual 虚函数父类和子类继承关系等。
这里还是以C++为例,进行接下来的介绍,其它语言实现运行期多态的方式各有不同,如果大家感兴趣,请评论留言,最重要的关注点点啊,大兄弟。你想知道的这里都有。
C++运行期多态,其实是通过虚函数表实现的,如果一个C++类中存在virtual 关键字定义的函数,此类默认会存在一个指向虚函数表的指针。
如何证明这件事呢? 有个好办法,看看汇编那就一目了然了,俗话说的好,汇编之下没秘密嘛。
说整就整,看下图:
然后看下对应的汇编中,类定义的部分:
首先,上面代码是没意义的哈,如果开启-O优化,那么汇编都会被优化掉了,请忽略优化。
然后我们来分析下,简单的汇编,就很一目了然了。可以看到父类TestVirtualPointer 保存了两个字段,第一个就是vtable(所谓的虚函数表指针,保存了实际虚函数表的地址),然后第二个字段是typeinfo name(实际就是指向了一个类名字的字符串),ConcreteVirtualObj类似。然后ConcreteVirtualObj 实现了虚函数,vtable 指向了虚函数表头指针位置。
编译期多态,就是靠着父类型的指针和引用指向子类型的指针和引用时,由于vtable 是类的第一个字段,所以此时父类的指针或者引用指向的具体实例对象是什么类型,在调用虚函数时,就会从对应子类型的vtable中找到对应的调用函数,达到运行期多态的效果。
运行期多态通过在一定意义上的类型擦除,实现了多态,把子类的类型全部擦除为父类型,然后在运行期,实例化对象的vtable 是谁的,就调用谁的函数这样。
下面给个简单的示例:
struct Parent {
virtual void print_name() {
std::cout << "parent\n";
}
};
struct Child : Parent {
void print_name() override {
std::cout << "child\n";
}
};
int main() {
Child child;
Parent& parent = child; // 父类型的引用指向子类型,
//或者指针(智能指针)都行,没有区别,这里偷个懒
parent.print_name();
return 0;
}
运行后会打印 child 字段。
那么C++编译期多态是什么呢?
编译期多态也称为静态多态,在一些需要多态特性设计扩展,但是又涉及高性能计算等领域,甚至连一个虚函数表跳转的指令都对运行性能有影响,而不允许使用虚函数时,那么就可以结合模板函数实现此种类型的多态。
编译期多态的优点就在于没有运行时开销,无虚函数指针,无需在运行时,跳转虚函数表查找需要执行的虚函数。但是缺点是:
一 要兜着点用,众所周知,模板会造成代码膨胀。
二. 编译时间的增长,模板的使用会延长编译时间。
三. 代码复杂度和问题定位变难,模板使用,或者元编程出现问题,大家都懂的,一堆报错看不懂。
下面给个简单的例子,大家一起看一下:
template<class T>
concept Switch = requires (T t) {
t.turn_on();
t.turn_off();
}; // 定义一个concept 限定模板类型
/*
定义一个模板类,此处具体含义可
简单理解成一个控制器,可以控制
所有开关的开启和关闭。
*/
template<Switch T>
class Control {
private:
T switcher_; // 此处的T 类型,就是编译期多态,
//根据构造时入参的不同,可以出现不同的调用结果
public:
Control(T switcher) : switcher_(std::move(switcher)) {}
void power_on() {
switcher_.turn_on();
}
void power_off() {
switcher_.turn_off();
}
};
template<class T>
Control(T t) -> Control<T>; // 我们的老朋友,CTAD
/*
定义一个具体的开关类,如下,灯光开关
*/
class LightSwitcher {
public:
void turn_on() {
std::cout << "light on\n";
}
void turn_off() {
std::cout << "light off\n";
}
};
int main() {
LightSwitcher light;
Control ctrl(light); // 通过CTAD,不需要显示指定类型
ctrl.power_on(); // 此处即可打印light on
ctrl.power_off(); // 此处即可打印light off
// 如上形成编译期多态,因为编译时,类型即可确定,调用关系也确定。
return 0;
这玩意儿就比较复杂了,给大家简单解释一下上面的代码。
我们想做的东西是,定义一个抽象的控制器,可以自动调用传入的所有抽象开关类(Switcher)并调用抽象开关类Switcher 的 turn_on 和 turn_off 方法。
然后为了展示多态, 我们定义了一个具体的灯光开关类,传入控制器中(Control类),即可通过Control类代理执行灯光的开启和关闭。
执行结果如下图所示:
这就是一个简单的编译期多态的实现,如果后期扩展,只要是实现了turn_on 和 turn_off方法的类,都可以传入后,多态调用。
上面用到了一些C++ 较新的特性,如果是C++低版本,需要使用一种叫做SFINAE 的技术进行Concept 和requires 的等效替换。
大家如果对SFINAE 技术不熟悉,就点个关注,劳烦劳烦,下一期给大家详细介绍。
跪求关注,希望各位看官顺手一点,你的关注是对我的最大鼓励。。。。
跪求关注。
猜你喜欢
- 2024-10-12 C++核心准则T.24:用标签类或特征区分只有语义不同的概念
- 2024-10-12 用苹果发布会方式打开C++20(苹果在哪开发布会)
- 2024-10-12 C++核心准则T.25:避免互补性约束(规矩是一种约束,一种准则)
- 2024-10-12 C++核心准则T.21:为概念定义一套完整的操作
- 2024-10-12 C++核心准则T.5:结合使用泛型和面向对象技术应该增强效果
- 2024-10-12 C++经典书籍(c++相关书籍)
- 2024-10-12 C++一行代码实现任意系统函数Hook
- 2024-10-12 C++核心准则T.11:只要可能就使用标准概念
- 2024-10-12 C++核心准则T.48:如果不能用概念,用enable_if
- 2024-10-12 C++核心准则T.13:简单、单类型参数概念使用缩略记法更好
你 发表评论:
欢迎- 最近发表
-
- 给3D Slicer添加Python第三方插件库
- Python自动化——pytest常用插件详解
- Pycharm下安装MicroPython Tools插件(ESP32开发板)
- IntelliJ IDEA 2025.1.3 发布(idea 2020)
- IDEA+Continue插件+DeepSeek:开发者效率飙升的「三体组合」!
- Cursor:提升Python开发效率的必备IDE及插件安装指南
- 日本旅行时想借厕所、买香烟怎么办?便利商店里能解决大问题!
- 11天!日本史上最长黄金周来了!旅游万金句总结!
- 北川景子&DAIGO缘定1.11 召开记者会宣布结婚
- PIKO‘PPAP’ 洗脑歌登上美国告示牌
- 标签列表
-
- ifneq (61)
- messagesource (56)
- aspose.pdf破解版 (56)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- vue回到顶部 (57)
- qcombobox样式表 (68)
- vue数组concat (56)
- tomcatundertow (58)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)