七、模板与泛型编程
条款45:运用成员函数模板接受所有兼容类型
让智能指针隐式转换
智能指针:
它是”行为像指针”的对象,并提供指针没有的机能。
真实指针的优点:
支持隐式转换,比如:

class Top  {  ...  };
class Middle: public Top  {  ...  };
class Bottom: public Middle  {  ...  };
Top* pt1 = new Middle;    // 将Middle* 转换为 Top*
Top* pt2 = new Bottom;    // 将Bottom* 转换为 Top*
const Top* pt2 = pt1;     // 将Top* 转换为const Top*

如果想在用户自定的智能指针中模拟上述转换:

template<typename T>
class SmartPtr  {
public:explicit SmartPtr(T* realPtr);    // 智能指针通常以内置指针完成初始化...
};
SmartPtr<Top> pt1 = SmartPtr<Middle>(new Middle);    // 将Middle转换为Top
SmartPtr<Top) pt2 = SmartPtr<Bottom>(new Bottom);    // 将Bottom转换为Top
SmartPtr<const Top> pct2 = pt1;    // 将Top转换为const Top

但是,同一个template的不同具现体之间并不存在什么与生俱来的固有关系。

固有关系:指如果以带有base-derived关系的B、D两类型分别具现化某个template,产生出来的两个具现体并不带有base-derived关系。
所以编译器将SmartPtr<Middle> 和 SmartPtr<Top> 看做两个完全不同的类,为了实现我们上述的转换能力,必须将它们明确地写出来。
Template和泛型编程
我们永远无法写出我们需要的所有构造函数。
因为一个template可被无限量具现化,以致生成无限量的函数。因此,似乎我们需要的不是为SmartPtr写一个构造函数,而是为它写一个构造模板。这样的模板是所谓member function templates,其作用是为class生成函数:

template<typename T>
class SmartPtr  {
public:template<typename U>SmartPtr(const SmartPtr<U>& other);    // 生成copy构造函数...
};

上述代码是指:对任何类型T和任何类型U,这里可以根据SmartPtr<U>生成一个SmartPtr<T> —— 因为 SmartPtr<T> 有个构造函数接受一个SmartPtr<U>参数。这一类构造函数根据对象u创建对象t,而u和v的类型是一个template的不同具现体,有时我们称之为泛化copy构造函数。

原始指针类型之间的转换是隐式转换,无需明白写出转型动作。在模板化构造函数中略去explicit就是为了这个目的。
我们希望根据一个SmartPtr 创建一个SmartPtr,却不希望根据一个SmartPtr创建一个SmartPtr。
因为那对public继承而言是矛盾的。我们也不希望根据一个SmartPtr创建一个SmartPtr,因为现实中并没有“将int* 转换为 double* ”的对应隐式转换行为。
所以,必须从某方面对这一member template所创建的成员函数群进行拣选或筛除。

通过在”构造模板”实现代码中约束转换行为:

template<typename T>
class SmartPtr  {
public:template<typename U>SmartPtr(const SmartPtr<U>& other) : heldPtr(other.get())    // 以other的heldPtr{  ...  }    // 初始化this的heldPtrT* get() const  {  return heldPtr;  }    ...
private:T* heldPtr;    // 这个SmartPtr持有的内置指针
};

使用成员初值列(member initialization list)来初始化SmartPtr<T> 之内类型为T* 的成员变量,并以类型为U* 指针(由SmartPtr 持有)作为初值。
这个行为只有当”存在某个隐式转换可将一个U* 指针转为一个T* 指针”时才能通过编译。
最终的效益是SmartPtr<T>现在有了一个泛化copy构造函数,这个构造函数只在其所获得的实参隶属适当类型时才通过编译。

member function templates(成员函数模板)的赋值操作

TR1的shared_ptr支持所有”来自兼容之内置指针、tr1::shared_ptrs、auto_ptrs 和 tr1::weak_ptrs”的构造行为,以及所有来自上述各物(tr1::weak_ptrs除外)的赋值操作。
下面是TR1规范中关于tr1::shared_ptr的一份摘录,其中强烈倾向声明template参数时采用关键字class而不采用typename

template<class T>
class shared_ptr  {
public:template<class Y> explicit shared_ptr(Y* p);template<class Y> shared_ptr(shared_ptr<Y> const& r);template<class Y> explicit shared_ptr(weak_ptr<Y> const& r);template<class Y> shared_ptr(auto_ptr<Y>& r);template<class Y> shared_ptr& operator = (shared_ptr<Y> const& r);template<class Y> shared_ptr& operator = (auto_ptr<Y>& r);...
};

上述所有构造函数都是explicit,唯有”泛化copyt构造函数”除外。它代表着从某个shared_ptr类型隐式转换至另一个shared_ptr类型是被允许的,但从某个内置指针或从其他智能指针类型进行隐式转换则不被认可。
传递给tr1::shared_ptr构造函数和assignment操作符的auto_ptrs并未声明为const,与之形成对比的则是tr1::shared_ptrs和tr1::weak_ptrs都以const传递。这是因为条款13说过,当你复制一个auto_ptrs,它们其实被改动了。
member templates并不改变语言规则,而语言规则说,如果程序需要一个copy构造函数,你却没有声明它,编译器会为你自动生成一个。在class内声明泛化copy构造函数并不会阻止编译器生成它们自己的copy构造函数,所以如果想要控制copy构造的所有,则必须同时声明泛化copy构造函数和正常的copy构造函数。相同规则也适用于赋值操作。

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

《Effective C++》学习笔记——条款45相关推荐

  1. Effective c++学习笔记条款20:宁以 pass-by-reference-to-const替换pass-by-value

    Prefer pass-by-reference-to-const to pass-by-value         这个问题在在C++是非常常见的.传值和传引用巨大的差别在于你所使用的参数是其本身还 ...

  2. Effective C++ 学习笔记 条款05 了解C++默默编写并调用了哪些函数

    当写下一个空类时,编译器会为你合成一个拷贝构造函数.一个拷贝赋值运算符.一个析构函数,如没有声明其他的构造函数,编译器会合成一个默认构造函数.这些都是inline的public成员. 当类有一个引用成 ...

  3. Effective C++ 学习笔记 第七章:模板与泛型编程

    第一章见 Effective C++ 学习笔记 第一章:让自己习惯 C++ 第二章见 Effective C++ 学习笔记 第二章:构造.析构.赋值运算 第三章见 Effective C++ 学习笔记 ...

  4. 深度学习笔记(45) 人脸验证与二分类

    深度学习笔记(45) 人脸验证与二分类 1. 二分类问题 2. 逻辑回归单元的处理 3. 计算技巧 1. 二分类问题 深度学习笔记(44) Triplet 损失 的Triplet loss是一个学习人 ...

  5. 【Effective C++ 学习笔记】

    条款02:尽量以const,enum,inline替换 #define #define定义的常量也许从未被编译器看见,也许在编译器开始处理源码之前它就被预处理器移走了: #define不重视作用域,不 ...

  6. Java:Effective java学习笔记之 考虑实现Comparable 接口

    Java 考虑实现Comparable 接口 考虑实现Comparable 接口 1.Comparable接口 2.为什么要考虑实现Comparable接口 3.compareTo 方法的通用约定 4 ...

  7. 《Effective C++》学习笔记——条款26

    ***************************************转载请注明出处:http://blog.csdn.net/lttree************************** ...

  8. Effective C++学习笔记(Part Five:Item 26-31)

    2019独角兽企业重金招聘Python工程师标准>>>  最近终于把effectvie C++仔细的阅读了一边,很惊叹C++的威力与魅力.最近会把最近的读书心得与读书笔记记于此, ...

  9. Effective C++学习笔记(Part One:Item 1-4)

    2019独角兽企业重金招聘Python工程师标准>>> 最近终于把effectvie C++仔细的阅读了一边,很惊叹C++的威力与魅力.最近会把最近的读书心得与读书笔记记于此,必备查 ...

最新文章

  1. python库numpy基本用法
  2. Ubuntu 8.10今起正式退休
  3. 用PHPcms V9四步完成WAP手机站搭建
  4. 四十二、ETL工具Kettle的转换步骤
  5. SAP Spartacus 的 Banner Component 请求
  6. File类的用法总结,及文件过滤器的介绍。
  7. iOS开发 字符串的转化 小技巧
  8. AngularJS指令范围中的#39;@#39;和#39;=#39;有什么区别?
  9. Linux怎么修改用户密码
  10. 实现自己的控制层do-c (仿Struts2和SpringMVC)(六)
  11. 同时启动两个android模拟器
  12. 目前电子计算机处于什么时代,目前,电子计算机处于哪大规模和超大规模集成电路时代。()...
  13. 《现代密码学》学习笔记——第七章 密钥管理[一]
  14. 树莓派接手机屏幕_使用诺基亚Nokia5110做树莓派的显示屏
  15. Apache Hadoop大数据集群及相关生态组件安装
  16. 华为路由器交换机配置命令
  17. UVM中超时退出set_timeout函数
  18. base64编码类------源代码(C#)
  19. C#面向对象程序设计课程实验二: 实验名称:Windows 窗体程序
  20. 二进制/八进制转换器

热门文章

  1. 上高职业技术学校计算机学几年,上高县职业技术学校简介|上高县职业技术学校介绍...
  2. 统计学中的第p百分位数的理解
  3. 服务器如何从安全模式增加用户名,win10安全模式里怎么添加账户_win10 安全模式如何添加用户-win7之家...
  4. 【HTTP协议其实很简单】03.自己写一个微型静态Web服务器
  5. Fluent的porous jump边界条件
  6. 说话技巧:成为谈话高手必不可少的十个特点
  7. 商品服务 - 销售属性维护,属性分组与属性关联
  8. 怎么释放gpu内存占用
  9. 25. Green Living 绿色生活
  10. curl+openssl,编译win32 兼容xp系统的静态库