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

   这是我在阅读Effective c++中认为比较重要的部分,下面给出了我对这一节的理解,并写出对应的比较容易理解的代码。

真实指针做得很好的一件事是,支持隐式转换,继承类指针可以隐式转换为基类指针,指向non-const对象的指针可以转换为指向const对象的指针。

例如有下面的一个三层继承体系中的一些转换:

class Top{};
class Middle:public Top{};
class Bottom:public Middle{};
Top*pt1 = new Middle;
Top*pt2 = new Bottom;
const Top* pct2 = pt1;

但是如果想在用户自定义的智能指针中模拟上述转换,稍稍有点麻烦,我们希望以下代码通过编译:

template<typename T>
class SmartPtr {
public:
	explicit SmartPtr(T* realPtr);
	...
};
SmartPtr<Top>pt1 = SmartPtr<Middle>(new Middle);
SmartPtr<Top>pt2 = SmartPtr<Bottom>(new Bottom);
SmartPtr<Top>pct2 = pt1;

但是同一个template的不同具现体之间并不存在什么与生俱来的固有关系,本例中就是SmartPtr<top>和SmartPtr<Middle>、SmartPtr<Bottom>之间并不存在什么关系。编译器视它们为完全不同的class。因此我们需要获得这个转换能力,解决方法是使用成员函数模板;如下:

template<typename T>
class SmartPtr {
public:
	template<typename U>
	SmartPtr(const SmartPtr& other);
	...
};

以上代码的意思是,对任何类型T和任何类型U,这里可以根据SmartPtr<U>生成一个SmartPtr<T>。  我们称此构造函数为泛化拷贝构造函数。

我们希望这个泛化拷贝构造函数能够遵守一定的规则,例如我们不希望父类可以向子类转换,我们也不希望根据SmartPtr<double>去创建一个SmartPtr<int>。我们通过对内置指针提供get和初始化列表来达到这个目的。例如下:

template<typename T>
class SmartPtr {
public:
	SmartPtr(T*p) :heldPtr(p) {}
	template<typename U>
	SmartPtr(const SmartPtr<U>& other):heldPtr(other.get()){ }	
	T* get()const {
		return heldPtr;
	}
private:
	T* heldPtr;
};

这个行为只有当“存在某个隐式转换可将一个U*指针转为一个T*指针”时才能通过编译,而这正是我们想要的。

请记住

请使用member function template(成员函数模板)生成"可几首所有兼容类型"的函数
 如果你声明member template用于"泛化copy构造"或"泛化assignment操作",你还需要声明正常copy构造函数和copy assignment操作符.

猜你喜欢

转载自blog.csdn.net/lkq_primer/article/details/81135152
今日推荐