《Effective C++》学习笔记——条款45
来源:互联网 发布:淘宝网如何注销账户 编辑:程序博客网 时间:2024/04/30 23:12
七、模板与泛型编程
条款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转换为TopSmartPtr<Top) pt2 = SmartPtr<Bottom>(new Bottom); // 将Bottom转换为TopSmartPtr<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的heldPtr T* 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
- 《Effective C++》学习笔记——条款15
- 《Effective C++》学习笔记——条款16
- 《Effective C++》学习笔记——条款17
- 《Effective C++》学习笔记——条款18
- 《Effective C++》学习笔记——条款19
- 《Effective C++》学习笔记——条款20
- 《Effective C++》学习笔记——条款21
- 《Effective C++》学习笔记——条款22
- 《Effective C++》学习笔记——条款23
- 《Effective C++》学习笔记——条款24
- 《Effective C++》学习笔记——条款25
- 《Effective C++》学习笔记——条款26
- 《Effective C++》学习笔记——条款27
- 《Effective C++》学习笔记——条款28
- 《Effective C++》学习笔记——条款29
- 《Effective C++》学习笔记——条款30
- 《Effective C++》学习笔记——条款31
- HDFS和hbase
- android开发查漏补缺图
- CentOS6.5 + Nginx1.10.2 + FastDFS5.08
- 5.视图
- HashSet
- 《Effective C++》学习笔记——条款45
- 技术的坚持
- 像素缓冲区对象(PBO)的异步Read-Back 源码解析
- Linux进程管理简介及进程管理工具
- Android 性能优化 内存优化 How to do
- Codeforces Round #379 (Div. 2)
- Linux内核移植--开机动画
- AngularJS 的基础使用
- 东秦第四届图灵杯-G-爬楼梯【DP】