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

【effective c++】条款四十五:运用成员函数模板接受所有兼容类型

文章目录

  • Effective C++ 条款45:运用成员函数模板接受所有兼容类型
    • 核心问题:模板类的"死板"
    • 解决方案:成员函数模板
      • 1. 使用成员函数模板接受所有兼容类型
      • 2. 仍需声明正常的拷贝构造和赋值操作符

请记住:
1. 请使用 member function templates(成员函数模板) 生成“可接受所有兼容类型” 的函数
2. 如果你声明 member templates 用于“泛化 copy 构造” 或“泛化 assignment操作”。 你还是需要声明正常的 copy构造函数和 copy assignment 操作符。

Effective C++ 条款45:运用成员函数模板接受所有兼容类型

核心问题:模板类的"死板"

在C++中,原生指针非常灵活,支持多种隐式转换:

  • 向上转型:派生类指针可以隐式转换为基类指针(如Derived*Base*)。
  • 常量化:非常量指针可以转换为常量指针(如int*const int*)。
classTop{};classMiddle:publicTop{};classBottom:publicMiddle{};Top*pt1=newMiddle;// ✅ 合法: 派生类指针转基类指针Top*pt2=newBottom;// ✅ 合法constTop*pct=pt1;// ✅ 合法: 非常量指针转常量指针

然而,对于模板类,情况就不同了。编译器将同一个模板的不同具体体现视为完全独立的、无关联的类型。例如,SmartPtr<Middle>SmartPtr<Top>在编译器看来就像stringvector一样毫无关系,因此它们之间无法进行隐式转换。

template<typenameT>classSmartPtr{public:explicitSmartPtr(T*realPtr);};SmartPtr<Top>pt1=SmartPtr<Middle>(newMiddle);// ❌ 编译错误!

这就导致了智能指针等模板类在使用上不如原生指针方便。

解决方案:成员函数模板

为了解决上述问题,条款45引入了成员函数模板

1. 使用成员函数模板接受所有兼容类型

通过在类模板内部定义一个成员函数模板(尤其是构造函数),可以让它接受所有兼容的类型。

template<typenameT>classSmartPtr{public:// 原始的、针对特定类型T的构造函数explicitSmartPtr(T*realPtr):heldPtr(realPtr){}// 关键的"泛化拷贝构造函数":这是一个成员函数模板template<typenameU>SmartPtr(constSmartPtr<U>&other):heldPtr(other.get()){// 核心: 利用U*到T*的隐式转换}// 提供get函数获取持有的原始指针T*get()const{returnheldPtr;}private:T*heldPtr;};

它是如何工作的?

  • “万能插座”:这个成员模板构造函数说:“只要你给我的SmartPtr<U>对象,其内部指针U*能隐式转换为我需要的T*,我就能用它来构造一个SmartPtr<T>对象。”
  • 自动类型安全检查:关键在heldPtr(other.get())这行初始化代码。编译器会尝试将U*转换为T*。只有当转换合法时(例如UT的派生类),编译才会通过。这保证了转换的安全性,避免了不合理的类型转换(如double*int*会报错)。

现在,之前的代码就可以工作了:

SmartPtr<Top>pt1=SmartPtr<Middle>(newMiddle);// ✅ 现在合法!SmartPtr<constTop>pct=pt1;// ✅ 也合法了!

2. 仍需声明正常的拷贝构造和赋值操作符

这是一个非常关键且容易遗漏的细节。

为什么需要?

  • 成员函数模板不会阻止编译器自动生成默认的拷贝构造函数和拷贝赋值运算符。
  • 当你进行同类型拷贝时(例如SmartPtr<Top> p1(p2)),编译器更倾向于使用它自动生成的默认拷贝构造函数,而不是你提供的泛化模板版本。
  • 如果你需要在拷贝时执行特殊逻辑(例如智能指针的引用计数管理),而只提供了泛化模板,那么同类型拷贝将不会执行你的特殊逻辑。

正确的做法是同时提供:

template<typenameT>classSmartPtr{public:// ... 其他成员 ...// 1. 正常的、针对同类型的拷贝构造函数SmartPtr(constSmartPtr&other):heldPtr(other.heldPtr){// ... 可能需要进行引用计数操作 ...}// 2. 泛化的拷贝构造函数 (用于兼容类型转换)template<typenameU>SmartPtr(constSmartPtr<U>&other):heldPtr(other.get()){// ... 可能需要进行引用计数操作 ...}// 对拷贝赋值运算符同理SmartPtr&operator=(constSmartPtr&other);template<typenameU>SmartPtr&operator=(constSmartPtr<U>&other);};

标准库中的std::shared_ptr就是严格遵循这一模式实现的。

http://www.jsqmd.com/news/473759/

相关文章:

  • 安卓wakelock 学习
  • 从空白文档到完整初稿:Paperzz 如何让毕业论文写作「零门槛」通关?
  • 创新GL微电网二次控制:基于事件触发的下垂控制及其最小事件触发间隔的扰动补偿研究“(具有参考文...
  • if-else条件语句详解
  • 【深度学习代码流程】李宏毅机器学习HW-1:预测美国COVID-19阳性病率
  • MATLAB/Simulink永磁直驱风力发电系统:SVPWM空间电压矢量调制与双闭环解耦控制应用
  • 从选题到成稿零焦虑:Paperzz 毕业论文初稿写作,让学术创作告别 “卡壳式内耗”
  • 开关磁阻电机电流斩波控制仿真 simulink仿真 双闭环控制等 含有文档报告,详细的参数说明
  • Vue3 + Vite 局域网 HTTPS 访问实战:手机秒连本地开发环境
  • 2026 学术写作破局:Paperzz 如何用「四步闭环法」解决毕业论文初稿难产,让你 3 天写完合格初稿
  • 【软件测试】系统学习清单(含知识点+掌握程度拆解)
  • # Vue 实现 PDF 预览与批量打印组件
  • 论文党「反内耗」神器:Paperzz 把毕业论文初稿写成「开卷答题」,4 步搞定从 0 到成稿
  • OpenClaw Skill 操作钉钉(原理+20个实例)
  • 数据预处理骚操作
  • 自动化仓储系统的核心设备堆垛机最怕啥?急起急停带来的机械冲击。老司机都知道S型曲线速度控制才是王道,今天咱就扒一扒西门子S7-1500里的实战代码
  • 高通跃龙QCS9100平台上工业缺陷检测实战(1): 从摄像头到端侧推理的最小闭环
  • 实测负荷数据(示例)
  • 北京上门回收老安宫牛黄丸、片仔癀!本草拾光商行高价收,变现快时效拉满 - 品牌排行榜单
  • 西门子PLC精确计算设备运行时间程序(1200PLC与1500PLC通用)——改良版实时时间比较法
  • C++学习日志——面向过程篇3.11
  • 架构2
  • ADRC双环自抗扰控制永磁同步电机矢量控制伺服系统Matlab仿真探索
  • IT系统全生命周期管理和运营方案(Word)
  • PYTHON学习笔记3
  • 代码随想录算法训练营第十天 | 用栈实现队列、 用队列实现栈、有效的括号、删除字符串中的所有相邻重复项
  • OFDM MQAM在衰落信道下误比特率性能仿真探索
  • python语法学习
  • Simulink双三相永磁同步电机控制仿真! 1.矢量控制,包括两种电机建模,VSD模型和双d...
  • STM32单片机开发的空气净化器:原理、设计与源码详解,适合开发人员