EffectiveC++学习笔记-条款45
2017-08-10 07:08
537 查看
条款45 运用成员函数模板接受所有兼容类型
假如我们实现自己的智能指针(和C++的shared_ptr做对比)
现在我们可以测试一下:
这里另外声明了一个模板参数Other,它可以与T相同,也可以不同,也就意味着它可以接受任何可以转化成T的类型了,比如父子类
还有对于get函数,因为拷贝构建中传入的对象不一定是属于同一个类的,所以不能保证可以访问到类的私有成员,需要提供一个get函数。
这是和内置的shared_ptr的行为是一致的。
还有一个重要的特征地方:在class类声明泛化copy构造函数(member template),并不会阻止编译器生成它们自己的copy构造函数(non-template),换言之,如果程序中只写了泛化的copy构造函数,那么编译器还是会自动生成一个非泛化的版本出来,如果不想要这个缺省版本,那一定不能偷懒,要两个版本的copy构造函数都要写。
如果你声明member templates用于“泛化copy构造”或“泛化assignment操作”,你还是需要声明正常的copy构造函数和copy assignment操作符。
运用成员函数模板接受所有兼容类型
有一个基类Widget和其子类Button://实现内容不重要 class Widget{}; class Button : public Widget{};
假如我们实现自己的智能指针(和C++的shared_ptr做对比)
template<typename T> class SmartPtr { public: SmartPtr(T* ptr) :m_ptr(ptr) { cout << "construct" << endl; } SmartPtr(const SmartPtr<T>& other) :m_ptr(other.get()) { cout << "copy" << endl; } //返回原始指针 T* get() const { return m_ptr; } //其他成员 private: T* m_ptr; }; 编译器不允许`SmartPtr<Widget> pt1 = SmartPtr<Button>(new Button);`因为在编译期替换T时,拷贝构造函数明确了接受类型必须是`SmartPtr<Widget>`,而由`SmartPtr<Button>`对象至`SmartPtr<Widget>`的转换并不存在,所以编译器报错。 为了转换合理我们必须让copy构造函数可以识别到父类的SmartPtr<Widget>,或者更多其他类。
template<typename Other> SmartPtr(Other* ptr) :m_ptr(ptr) { cout << "construct SmartPtr" << endl; } template<typename Other> SmartPtr(const SmartPtr<Other>& other) : m_ptr(other.get()) { cout << "copy SmartPtr" << endl; }
现在我们可以测试一下:
SmartPtr<Widget> pt1 = SmartPtr<Button>(new Button); cout << "-------------" << endl; SmartPtr<Widget> pt2(new Button); cout << "-------------" << endl; SmartPtr<Button> pt3 = SmartPtr<Button>(new Button); cout << "-------------" << endl; SmartPtr<Widget> pt4 = pt3; cout << "-------------" << endl; //打印结果 construct copy SmartPtr ------------- construct SmartPtr ------------- construct ------------- copy SmartPtr -------------
这里另外声明了一个模板参数Other,它可以与T相同,也可以不同,也就意味着它可以接受任何可以转化成T的类型了,比如父子类
还有对于get函数,因为拷贝构建中传入的对象不一定是属于同一个类的,所以不能保证可以访问到类的私有成员,需要提供一个get函数。
这是和内置的shared_ptr的行为是一致的。
还有一个重要的特征地方:在class类声明泛化copy构造函数(member template),并不会阻止编译器生成它们自己的copy构造函数(non-template),换言之,如果程序中只写了泛化的copy构造函数,那么编译器还是会自动生成一个非泛化的版本出来,如果不想要这个缺省版本,那一定不能偷懒,要两个版本的copy构造函数都要写。
总结
请使用member function templates(成员函数模板)生成“可接受所有兼容类型”的函数;如果你声明member templates用于“泛化copy构造”或“泛化assignment操作”,你还是需要声明正常的copy构造函数和copy assignment操作符。
标准shared_ptr的实现
// TEMPLATE CLASS shared_ptr template<class _Ty> class shared_ptr : public _Ptr_base<_Ty> { // class for reference counted resource management public: typedef shared_ptr<_Ty> _Myt; typedef _Ptr_base<_Ty> _Mybase; constexpr shared_ptr() _NOEXCEPT { // construct empty shared_ptr } **template<class _Ux> explicit shared_ptr(_Ux *_Px) { // construct shared_ptr object that owns _Px _Resetp(_Px); }** template<class _Ux, class _Dx> shared_ptr(_Ux *_Px, _Dx _Dt) { // construct with _Px, deleter _Resetp(_Px, _Dt); } constexpr shared_ptr(nullptr_t) _NOEXCEPT { // construct empty shared_ptr } template<class _Dx> shared_ptr(nullptr_t, _Dx _Dt) { // construct with nullptr, deleter _Resetp((_Ty *)0, _Dt); } template<class _Dx, class _Alloc> shared_ptr(nullptr_t, _Dx _Dt, _Alloc _Ax) { // construct with nullptr, deleter, allocator _Resetp((_Ty *)0, _Dt, _Ax); } template<class _Ux, class _Dx, class _Alloc> shared_ptr(_Ux *_Px, _Dx _Dt, _Alloc _Ax) { // construct with _Px, deleter, allocator _Resetp(_Px, _Dt, _Ax); } template<class _Ty2> shared_ptr(const shared_ptr<_Ty2>& _Right, _Ty *_Px) _NOEXCEPT { // construct shared_ptr object that aliases _Right this->_Reset(_Px, _Right); } shared_ptr(const _Myt& _Other) _NOEXCEPT { // construct shared_ptr object that owns same resource as _Other this->_Reset(_Other); } **template<class _Ty2, class = typename enable_if<is_convertible<_Ty2 *, _Ty *>::value, void>::type> shared_ptr(const shared_ptr<_Ty2>& _Other) _NOEXCEPT { // construct shared_ptr object that owns same resource as _Other this->_Reset(_Other); }** template<class _Ty2> explicit shared_ptr(const weak_ptr<_Ty2>& _Other, bool _Throw = true) { // construct shared_ptr object that owns resource *_Other this->_Reset(_Other, _Throw); } #if _HAS_AUTO_PTR_ETC template<class _Ty2> shared_ptr(auto_ptr<_Ty2>&& _Other) { // construct shared_ptr object that owns *_Other.get() this->_Reset(_STD move(_Other)); } #endif /* _HAS_AUTO_PTR_ETC */ shared_ptr(_Myt&& _Right) _NOEXCEPT : _Mybase(_STD move(_Right)) { // construct shared_ptr object that takes resource from _Right } template<class _Ty2, class = typename enable_if<is_convertible<_Ty2 *, _Ty *>::value, void>::type> shared_ptr(shared_ptr<_Ty2>&& _Right) _NOEXCEPT : _Mybase(_STD move(_Right)) { // construct shared_ptr object that takes resource from _Right } template<class _Ux, class _Dx, class = typename enable_if<is_convertible< typename unique_ptr<_Ux, _Dx>::pointer, _Ty *>::value, void>::type> shared_ptr(unique_ptr<_Ux, _Dx>&& _Right) { // construct from unique_ptr _Resetp(_Right.release(), _Right.get_deleter()); } template<class _Ux, class _Dx> _Myt& operator=(unique_ptr<_Ux, _Dx>&& _Right) { // move from unique_ptr shared_ptr(_STD move(_Right)).swap(*this); return (*this); } _Myt& operator=(_Myt&& _Right) _NOEXCEPT { // take resource from _Right shared_ptr(_STD move(_Right)).swap(*this); return (*this); } template<class _Ty2> _Myt& operator=(shared_ptr<_Ty2>&& _Right) _NOEXCEPT { // take resource from _Right shared_ptr(_STD move(_Right)).swap(*this); return (*this); } ~shared_ptr() _NOEXCEPT { // release resource this->_Decref(); } _Myt& operator=(const _Myt& _Right) _NOEXCEPT { // assign shared ownership of resource owned by _Right shared_ptr(_Right).swap(*this); return (*this); } template<class _Ty2> _Myt& operator=(const shared_ptr<_Ty2>& _Right) _NOEXCEPT { // assign shared ownership of resource owned by _Right shared_ptr(_Right).swap(*this); return (*this); } #if _HAS_AUTO_PTR_ETC template<class _Ty2> _Myt& operator=(auto_ptr<_Ty2>&& _Right) { // assign ownership of resource pointed to by _Right shared_ptr(_STD move(_Right)).swap(*this); return (*this); } }
相关文章推荐
- EffectiveC++学习笔记-条款26|27
- EffectiveC++学习笔记-条款7
- EffectiveC++学习笔记-条款32|33
- EffectiveC++学习笔记-条款4
- EffectiveC++学习笔记-条款20|21
- EffectiveC++学习笔记-条款38
- EffectiveC++学习笔记-条款36|37
- EffectiveC++学习笔记-条款13
- EffectiveC++学习笔记-条款28|29
- EffectiveC++学习笔记-条款15|16|17
- EffectiveC++学习笔记-条款22|23
- EffectiveC++学习笔记-条款12
- EffectiveC++学习笔记-条款41|42
- Effecticve学习笔记_条款45:运用成员函数模板接收所有兼容类型
- EffectiveC++学习笔记-条款46
- EffectiveC++学习笔记-条款24|25
- EffectiveC++学习笔记-条款14
- EffectiveC++学习笔记-条款8
- EffectiveC++学习笔记-条款18|19
- EffectiveC++学习笔记-条款49