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

Item45--运用成员函数模板接受所有兼容类型

1.人话版

1. 遇到的问题:模板类太死板

在 C++ 里,如果你有父类 Animal 和子类 Dog

  • 原生指针很聪明: 你把 Dog* 赋值给 Animal* 是理所当然的(向上转型)。
  • 模板类很死板: 编译器觉得 SmartPtr<Dog>SmartPtr<Animal> 是两个完全没关系的类。你直接把“狗狗智能指针”给“动物智能指针”,编译器会报错。

这就不爽了,我们希望智能指针能像原生指针一样,支持这种“子类转父类”的操作。

2. 条款 45 的对策:做一个“万能插座”

为了解决这个问题,我们需要在类里面写一个“万能构造函数”(专业叫法:成员函数模板)。

它的意思就是告诉编译器:

“我不只接受 SmartPtr<Animal>,只要别人给我的那个类型 U 能转成我现在的类型 T,我就都能收!”

代码长这样(简化版):

template<typename T>
class SmartPtr {
public:// 这就是一个“万能插座”template<typename U>SmartPtr(const SmartPtr<U>& other) : heldPtr(other.get()) { // 核心:尝试把 U* 传给 T*}T* get() const { return heldPtr; }
private:T* heldPtr;
};

3. 安全性:它不会“乱转”

你可能会问:“万一我把 SmartPtr<猫> 传给 SmartPtr<狗> 怎么办?”

别担心,编译器会帮你把关。 在上面的代码里,有一句 : heldPtr(other.get())。这行代码实际上是在尝试把一个 U* 指针赋值给 T* 指针。

  • 如果 UDogTAnimal,原生指针能转,代码就编译通过。
  • 如果 UCatTDog,原生指针转不动,编译器会直接在这里报错

总结成一句话:

条款 45 就是教你给模板类写一个“通用的构造函数”,利用原生指针的转换规则,让你的模板类也能灵活地处理各种有继承关系的类型转换。

最典型的例子就是 std::shared_ptr,你可以把 shared_ptr<子类> 传给需要 shared_ptr<父类> 的地方,这就是靠这个条款实现的。

2.详解版

为什么需要这个条款?

在原生指针中,存在一种自然的隐式转换关系:

  • 向上转型 (Upcasting):指向派生类的指针可以自动转换为指向基类的指针(例如 Derived*Base*)。
  • 常量化:非常量指针可以转换为常量指针(例如 int*const int*)。

然而,当你使用模板类(如 SmartPtr<T>)时,情况就不同了。在编译器看来,SmartPtr<Derived>SmartPtr<Base>完全不同的两个类,它们之间没有任何继承关系。如果你不额外处理,就无法将一个派生类的智能指针赋值给基类的智能指针。


核心解决方案:成员函数模板

为了模拟原生指针的这种灵活性,我们需要在类模板中定义成员函数模板 (Member Function Templates)

1. 编写泛化拷贝构造函数

我们需要一个构造函数,让 SmartPtr<T> 可以由 SmartPtr<U> 构造出来。

template<typename T>
class SmartPtr {
public:// 泛化拷贝构造函数 (Generalized Copy Constructor)template<typename U>SmartPtr(const SmartPtr<U>& other): heldPtr(other.get()) { // 用 U* 初始化 T*// ...}T* get() const { return heldPtr; }private:T* heldPtr; // 内含的原生指针
};

2. 利用编译器进行类型约束

你可能担心:上面的代码是不是允许“任何”类型转换?比如把 SmartPtr<double> 转换成 SmartPtr<int>

答案是:不会。 关键在于初始化列表:: heldPtr(other.get())

  • 如果 U* 无法隐式转换为 T*(例如 double* 无法隐式转为 int*,或者 Base* 无法转为 Derived*),这段代码将无法通过编译
  • 这正是我们想要的:利用底层原生指针的转换规则来约束模板类的转换规则。

进阶应用:赋值操作

除了构造函数,赋值操作(operator=)也需要支持泛化。

template<typename T>
class SmartPtr {
public:template<typename U>SmartPtr& operator=(const SmartPtr<U>& other) {// 利用底层指针赋值,若类型不兼容则报错heldPtr = other.get(); return *this;}// ...
};

⚠️ 重要的注意事项:不要遗漏常规拷贝

这是一个常见的误区:成员函数模板不会抑制编译器生成默认的拷贝构造函数。

如果你只声明了泛化拷贝构造函数(template<typename U> SmartPtr(const SmartPtr<U>&)),当你尝试用一个 SmartPtr<T> 去拷贝另一个 SmartPtr<T>(相同类型)时,编译器仍会为你自动生成一个默认的拷贝构造函数。

如果你想要控制相同类型的拷贝行为(例如实现深度拷贝或引用计数递增),你必须同时声明:

  1. 普通的拷贝构造函数(相同类型)。
  2. 泛化的拷贝构造函数(兼容类型)。
template<typename T>
class SmartPtr {
public:// 1. 普通拷贝构造函数SmartPtr(const SmartPtr& other);// 2. 泛化拷贝构造函数template<typename U>SmartPtr(const SmartPtr<U>& other);// 赋值操作同理...
};

总结

  • 目的:让模板类(如智能指针、迭代器)支持像原生指针那样的隐式转换。
  • 手段:使用成员函数模板。
  • 安全性:在实现中利用底层指针的初始化或赋值,让编译器自动检查类型兼容性。
  • 细节:泛化模板不会替代普通的拷贝构造/赋值函数,如需特殊逻辑,两者都要手动实现。

这个条款在 std::shared_ptrstd::unique_ptr 以及 STL 迭代器的设计中得到了广泛应用。

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

相关文章:

  • 大数据领域Kafka与Hadoop的协同工作模式
  • 霍华德·马克斯的市场周期定位技巧
  • 别乱花钱了!6款实测有效的降ai工具推荐,学姐教你降低ai率!
  • 强烈推荐 wxWidgets
  • SFTDataset:Verl 单轮Dataset vs rllm 多轮Dataset vs Parallel-R1 Dataset
  • Boost asio定时器
  • 2025年度江西南昌育儿嫂企业TOP5评测!金牌一站式早教型育儿嫂品牌榜单发布,赋能现代家庭育儿新生态 - 全局中转站
  • 2025年度江西南昌老人护理企业TOP7评测!专业照护+经验沉淀优质品牌榜单发布,用心守护构筑长者幸福晚年 - 全局中转站
  • Product Hunt 每日热榜 | 2025-12-20
  • 过半的家庭都踩过近视的“坑”,每位爸妈都值得注意!
  • 每天一个网络知识:什么是光猫?
  • 【2025全网盘点】10款常见降AI率工具大汇总(含笔灵/Kimi等免费降AI版本)
  • Item28--避免返回 handles 指向对象内部成分
  • 前端开发随笔
  • 基于java的SpringBoot/SSM+Vue+uniapp的大学生学业预警和警告平台的详细设计和实现(源码+lw+部署文档+讲解等)
  • 一文吃透动态规划解题思路——以钢条切割问题为例
  • Redis:安装配置、核心概念与实践应用
  • 程序员的幸福之道:不必追逐权力与学历——在代码与生活之间寻找真正的自由
  • 别再焦虑了!6款实测有效的降ai工具推荐,学姐手把手教你降低ai率!
  • 孩子近视的“真凶”不是手机,也不是电视,而是父母都不在意的它
  • 基于java的SpringBoot/SSM+Vue+uniapp的课程目标达成度系统的详细设计和实现(源码+lw+部署文档+讲解等)
  • 动态规划解决最小编辑距离问题
  • 拒绝智商税!6款实测有效的降ai工具推荐,保姆级手把手教你降低ai率!
  • dockerfile多阶段构建 + UBI 9(在指定的根目录中卸载 setup 包`rpm --root /mnt/rootfs -e --nodeps setup`)
  • 防控近视你需要知道的这些科普常识!
  • 基于java的SpringBoot/SSM+Vue+uniapp的本科生毕业论文管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
  • 别花冤枉钱!6款实测有效的降ai工具推荐,0基础手把手教你降低ai率!
  • Item23--宁以 non-member、non-friend 替换 member 函数
  • 无金融背景想入行?2025年靠这几张AI证书实现转行突破
  • 【Memory协议栈】AUTOSAR架构下NvM_ReadAll时间优化的实用方案