【C++奇技淫巧】CRTP(奇特重现模板模式)

CRTP(Curiously Recurring Template Pattern,奇特重现模版模式),是一种在C++中使用模板来实现的设计模式,主要用于实现编译时多态性(静态多态)。这种模式通过类模板和模板继承机制来实现,使得派生类在继承时将自身作为基类模板的参数。

这里采用的中文名字参考了zh.cppreference.com

示例解析

template <typename T>
class Base {
public:void doSomething(){// 访问 Derived 类的成员static_cast<T*>(this)->implementation();}
};class Derived : public Base<Derived> {
public:void implementation(){std::cout << "Derived::implementation()";}
};int main()
{Derived d;d.doSomething();return 0;
}

输出结果:

Derived::implementation()

解析

编译器在编译上面代码时,因为延迟实例化,所以在Derived派生类后面实例化Base<Derived>
在实例化的Base<Derived>类的doSomething()函数中,将this指针从Base<Derived>*转换成Derived*,这样就能访问Derived类中定义的方法了。

CRTP的多态性

C++多态的实现方式分为动态多态(虚函数)、静态多态(模板、函数重载)。
其中用模板实现静态多态的方式也有很多种:

  1. 函数模板
  2. 类模板
  3. CRTP(通过模板继承实现)

动态多态和静态多态

动态多态

动态多态是通过虚函数来实现的。它允许在运行时确定调用哪个对象/方法,这主要依赖于虚函数表(vtable)来动态解析调用。

优点:
  1. 灵活性:可以在运行时改变对象的行为
  2. 易于使用:只需声明虚函数,让派生类重写函数即可
缺点:
  1. 性能开销:每次调用虚函数时都需要通过虚指针转到虚函数表,再找到对应的函数,花费时间长
  2. 内存开销:每个对象都需要额外的内存来存储指向虚函数表的指针。

静态多态

静态多态通常是通过模板实现的,它在编译时就明确了调用的对象/方法,而不是在运行时。

优点:
  1. 性能开销:没有运行时的多余开销,函数调用可以直接解析
  2. 内存开销:运行时不会有多余的内存开销
缺点:
  1. 代码膨胀:对于每个不同的类型,编译器可能都会生成一份代码,这可能导致最终编译出的二进制文件体积增大
  2. 灵活性较低:在编译时就已经确定了所有的类型,不能像动态多态那样在运行时改变对象的行为

CRTP和虚函数

性能与开销

  • CRTP:使用 CRTP 实现的是静态多态,即在编译时就解析函数调用,而不需要虚函数表,从而避免了运行时的查找开销。这种方法通过模板实例化直接绑定函数,因此运行效率更高,没有额外的内存开销。
  • 虚函数:动态多态通过虚函数实现。虚函数依赖于虚函数表(vtable),这意味着每次调用虚函数时都需要通过虚函数表进行间接跳转。这种间接性带来运行时开销,同时每个使用虚函数的对象需要额外的内存来存储指向虚函数表的指针。

灵活性和可维护性

  • CRTP:CRTP 允许基类通过模板机制访问派生类的成员,这样可以将一些通用的功能封装在基类中,而具体的实现则在派生类中完成。CRTP 特别适合于实现混入(Mixins)类型的功能,能够在不修改原有类结构的情况下,为类增加额外的功能。
  • 虚函数:虚函数提供了极高的灵活性,允许在运行时决定对象的行为。这使得代码可以容易地扩展和修改,但可能导致代码维护和理解的复杂度增加。

代码重用与扩展

  • CRTP:CRTP 允许基类通过模板机制访问派生类的成员,这样可以将一些通用的功能封装在基类中,而具体的实现则在派生类中完成。CRTP 特别适合于实现混入(Mixins)类型的功能,能够在不修改原有类结构的情况下,为类增加额外的功能。

上面提到的混入(Mixins)指的是在面向对象编程中用于增加类功能的技术,它通过多重继承将功能模块(Mixin类)混入到一个类中。这种方法允许程序员在不修改原始类代码的情况下为类添加新的行为和属性。

  • 虚函数:通过虚函数,派生类可以覆盖基类中的行为,实现功能的自定义和扩展。这种方法简洁直观,易于理解和使用。

类型安全和错误检测

  • CRTP:由于 CRTP 是在编译时处理的,所以相关的类型错误会在编译阶段被捕捉和报告,增加了开发过程中的类型安全性。
  • 虚函数:虚函数的错误(如类型不匹配)通常在运行时发现,有时这可能导致程序崩溃或不稳定。

CRTP的案例展示

enable_shared_from_this

enable_shared_from_this就是一个典型的CRTP案例,继承enable_shared_from_this类的对象可以从内部生成std::shared_ptr

这个模板类最初是Boost库引入的,后面被纳入到C++标准库中,下面我们展示Boost库下的源码

namespace boost
{template<class T> class enable_shared_from_this
{
protected:BOOST_CONSTEXPR enable_shared_from_this() BOOST_SP_NOEXCEPT{}BOOST_CONSTEXPR enable_shared_from_this(enable_shared_from_this const &) BOOST_SP_NOEXCEPT{}enable_shared_from_this & operator=(enable_shared_from_this const &) BOOST_SP_NOEXCEPT{return *this;}~enable_shared_from_this() BOOST_SP_NOEXCEPT // ~weak_ptr<T> newer throws, so this call also must not throw{}public:shared_ptr<T> shared_from_this(){shared_ptr<T> p( weak_this_ );BOOST_ASSERT( p.get() == this );return p;}shared_ptr<T const> shared_from_this() const{shared_ptr<T const> p( weak_this_ );BOOST_ASSERT( p.get() == this );return p;}weak_ptr<T> weak_from_this() BOOST_SP_NOEXCEPT{return weak_this_;}weak_ptr<T const> weak_from_this() const BOOST_SP_NOEXCEPT{return weak_this_;}public: // actually private, but avoids compiler template friendship issues// Note: invoked automatically by shared_ptr; do not calltemplate<class X, class Y> void _internal_accept_owner( shared_ptr<X> const * ppx, Y * py ) const BOOST_SP_NOEXCEPT{if( weak_this_.expired() ){weak_this_ = shared_ptr<T>( *ppx, py );}}private:mutable weak_ptr<T> weak_this_;
};} // namespace boost

下面展示使用标准库中的enable_shared_from_this示例:

#include <memory>
#include <iostream>class MyClass : public std::enable_shared_from_this<MyClass> {
public:std::shared_ptr<MyClass> get_shared_ptr() {return shared_from_this();}
};int main() {std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>();std::shared_ptr<MyClass> another_ptr = ptr->get_shared_ptr();std::cout << "Same object: " << (ptr == another_ptr) << std::endl;
}

日志类

template<typename T>
class Logging {
public:void log(const std::string& message) const {// 获取派生类的名称,这里假设派生类有一个名为 getName 的方法std::cout << static_cast<const T*>(this)->getName() << ": " << message << std::endl;}
};class Car : public Logging<Car> {
public:Car(const std::string& model) : model_(model) {}std::string getName() const { return model_; }void drive() {this->log("Starting the engine.");// 驾驶逻辑...this->log("Stopped the engine.");}private:std::string model_;
};class Robot : public Logging<Robot> {
public:Robot(const std::string& identifier) : identifier_(identifier) {}std::string getName() const { return identifier_; }void operate() {this->log("Activating robot.");// 操作逻辑...this->log("Deactivating robot.");}private:std::string identifier_;
};int main() {Car car("Toyota Camry");car.drive();Robot robot("Android 007");robot.operate();return 0;
}

总结

我总结了CRTP的具体应用场景:

  1. 使用虚函数有性能问题,需要优化,可以将虚函数转成CRTP(后续文章会介绍)
  2. 能够抽象出通用方法,派生类只使用方法,不重写/修改方法
  3. 需要基于现有的通用方法来添加新功能(不改变通用方法)

其实在使用CRTP和虚函数的核心区别是,CRTP的继承关系中能够抽象出通用方法,且不会修改通用方法;而虚函数是抽象出通用方法,但要重写方法,只是把通用方法当做一个入口。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/19707.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【html知识】html中常用的表单元素+css格式美化

创作背景与目的&#xff1a; 随着互联网的飞速发展&#xff0c;表单作为网页交互的重要组成部分&#xff0c;扮演着收集用户信息、进行用户反馈的关键角色。本作品旨在总结并展示HTML中常用的表单元素&#xff0c;帮助开发者快速了解并应用这些元素&#xff0c;以优化网页的交…

自学成才Flutter 弹性布局、线性布局

本文我们要介绍 Flutter 中布局 Widget&#xff0c;包括弹性布局、线性布局 流式布局和层叠布局。 Flutter中文网 Flutter开发 一、弹性布局--Flex Flex 类似 Android 中的 FlexboxLayout&#xff0c;和 Expanded 配合使用可以实现子Widget 按照一定比例来分配父容器空间。 使…

数仓建模—企业数字化转型的本质

数仓建模—企业数字化转型的本质 数字化转型与数字化、数字化建设、数字化管理到底有什么差别?企业的数字化建设重点关注哪两个层面的实现?数字化转型中的“转型”到底指的是什么?数字化转型对企业有哪些最重要的挑战?转型的终极目标是什么?客户价值实现是转型的结果还是逻…

Web前端三大主流框架:React、Vue和Angular

在当前的Web开发领域&#xff0c;前端框架的选择对于项目的成功至关重要。作为一名资深的IT技术员&#xff0c;我对前端技术的发展和行业趋势保持着持续的关注。本文将介绍当前Web前端三大主流框架&#xff1a;React、Vue和Angular&#xff0c;并分析它们各自的优势。 React&a…

MyBatis通用Mapper:简化数据库操作的利器

引言 在软件开发中&#xff0c;数据库操作是不可或缺的一部分。通常我们会使用mybatis&#xff0c;的MBG插件&#xff0c;自动生成表对应的基本操作语句xml。 当我们的表字段发生变化的时候&#xff0c;我们需要修改实体类和Mapper文件定义的字段和方法。如果是增量维护&…

【学习笔记】数据结构(一)

基本概念和术语 &#x1f449;数据&#xff1a;所有能被输入到计算机中&#xff0c;且被计算机处理的符号的集合&#xff1b; 是计算机操作对象的总称&#xff1b;是计算机处理信息的载体&#xff1b;是信息的某一种特定的符号表示形式包括数值型数据、非数值型数据 &#x1…

git生成密钥(免密)

生成SSH密钥对的方法如下&#xff1a; 打开Git Bash。 输入以下命令生成新的SSH密钥对&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 这里的 -C 参数后面跟的是你的邮箱地址&#xff0c;通常用于标识这个密钥。 当系统提示你“Enter a fil…

汇编概论和实践

一 汇编第一例 C代码 #include <stdio.h>int main() {printf("Hello, World!\n");return 0; }对应的汇编 .LC0:.string "Hello, World!"main:pushq %rbpmovq %rsp, %rbpleaq .LC0(%rip), %rdicall puts@PLTmovl $0, %eaxpopq %rbpret 二 CPU架构…

Apache Pulsar 中文社区有奖问卷调查(2024 上半年度)

Apache Pulsar 中文社区有奖问卷调查&#xff08;2024 上半年度&#xff09; &#x1f4e3; &#x1f4e3; &#x1f4e3; Hi&#xff0c;Apache Pulsar 社区的小伙伴们&#xff0c;社区 2024 上半年度的有奖问卷调查来啦&#xff01; &#x1f64c; 本次调查旨在了解用户使用 …

涂装线体智能化管理:RFID技术的典范案例

涂装线体智能化管理&#xff1a;RFID技术的典范案例 汽车涂装是汽车制造过程中极为关键的一环&#xff0c;涉及多道工序&#xff0c;如预处理、电泳、中涂、面漆等&#xff0c;每一步都需要精确控制以确保车身表面的质量和美观。传统方式下&#xff0c;车辆在不同工位间的流转依…

新火种AI|OpenAI要和苹果合作了?微软有些不高兴

作者&#xff1a;一号 编辑&#xff1a;美美 和苹果之间的合作&#xff0c;可能会称为Altman引以为傲的功绩。 根据 The Information 援引知情人士的消息&#xff0c;OpenAI 已经和苹果达成了协议&#xff0c;将在其产品中运用 OpenAI 的对话式 AI。 如果进展顺利&#xff…

vue-cli搭建的项目如何去掉vue默认的favicon.ico

vue-cli搭建的项目如何去掉vue默认的favicon.ico 一、删除 public 目录下的 favicon.ico 文件二、替换<link> 要在 Vue CLI 生成的项目中移除默认的 favicon.ico 并使用浏览器默认图标&#xff08;如 Google 默认图标&#xff09;&#xff0c;您可以按照以下步骤进行&…

SpringBoot案例,通关版

项目目录 此项目为了伙伴们可以快速入手SpringBoot项目,全网最详细的版本,每个伙伴都可以学会,这个项目每一步都会带大家做,学完后可以保证熟悉SpringBoot的开发流程项目介绍:项目使用springboot mybatis进行开发带你一起写小项目先把初始环境给你们第一步新建springboot项目返…

基于知识图谱分析贸易关系走向

基于知识图谱分析贸易关系走向 前言一、基础数据二、贸易规则三、知识图谱可视化四、完整代码 前言 知识图谱是一种用图模型来描述知识和建模世界万物之间的关联关系的技术方法。在贸易关系的分析中&#xff0c;知识图谱可以将各个国家、地区、商品、贸易政策等作为节点&#…

人脸识别模型与人类视觉识别的对比——评估人脸识别模型存在偏见是否比人类的偏见大?

1. 概述 人脸识别系统是一个几十年来一直备受关注的研究领域。而且在过去的几年中。公司和政府一直在积极引入人脸识别系统&#xff0c;并且我们看到越来越多的机会可以看到人脸识别系统。例如&#xff0c;有的系统可以随便介绍&#xff0c;如搜索特定人的图像&#xff08;图像…

Appium安装及配置(Windows环境)

在做app相关自动化测试&#xff0c;需要使用appium来做中转操作&#xff0c;下面来介绍一下appium的环境安装配置 appium官方文档&#xff1a;欢迎 - Appium Documentation 一、下载appium 下载地址&#xff1a;https://github.com/appium/appium-desktop/releases?page3 通…

网络安全岗秋招面试题及面试经验分享

Hello&#xff0c;各位小伙伴&#xff0c;我作为一名网络安全工程师曾经在秋招中斩获&#x1f51f;个offer&#x1f33c;&#xff0c;并在国内知名互联网公司任职过的职场老油条&#xff0c;希望可以将我的面试的网络安全大厂面试题和好运分享给大家~ 转眼2024年秋招又快到了金…

计算机网络基础知识(持续更新中)

目录 前言 第一章&#xff1a;概述 一、因特网概述 二、三种交换方式 前言 为夯实计算机网络基础知识&#xff0c;本篇跟随b站的胡科大教书匠走进计算机网络的世界&#xff0c;仅记录计算机网络中的重点知识。 第一章&#xff1a;概述 一、因特网概述 1. 网络、互联网&am…

悬剑武器库5.04版

工具介绍 悬剑5 基于“悬剑网盘”精选工具集悬剑5“飞廉”云武器库制作。 操作系统&#xff1a;Windows 10 专业版 锁屏密码&#xff1a;secquan.org 解压密码: 圈子社区secquan.org 镜像大小&#xff1a;33.1GB 系统占用空间63.0 GB 镜像导入 下载镜像&#xff0c;文末…

TinTinLand Web3 + AI 共学月|五周上手,捕获浪潮碰撞下的无限机遇

近期&#xff0c;斯坦福大学人文x人工智能研究所&#xff08;Stanford HAI&#xff09;发布了《2024 年人工智能指数报告》&#xff08;Artificial Intelligence Index Report 2024&#xff09;&#xff0c;指出当前人工智能的发展已全面改变社会的前沿风向&#xff0c;其中据 …