智能指针是行为像指针的对象,真的指针做的很好的事情是:支持隐式转换,派生类指针可以隐式转换为基类指针,指向non-const对象的指针可以转换为指向const对象等等,比如:
class Top {...};
class Middle : public Top{...};
class Bottom : public Middle{...};
Top * t1 = new Middele;
Top * pt2 = new Bottom;
const Top * pct2 = pt1;
但是如果想自定的智能指针做类似上面的事情,有点困难,你可能会希望以下代码通过编译:
template<typename T>
class SmartPrt
{
public:
explicit SmartPtr(T * realPtr);
...
};
SmartPtr<Top>pt1 = SmartPtr<Middle>(new Middle);
SmartPtr<Top>pt2 = SmartPtr<Bottom>(new Middle);
SmartPtr<const Top>pct2 = pt1;
但是,同一个模板的不同具现化之间并不存在什么固有关系,不要认为带有派生关系的AB类型分别具现化某个模板,然后模板也是有派生关系。
那么如何解决这个问题呢?
我们必须将他们明确编写出来,我们需要为SmartPtr写一个构造模板,这样的模板是所谓的成员函数模板,它的作用是为类生成函数:
template<typename T>
class SmartPrt
{
public:
template<typename U>
SmartPtr(const SmartPtr<U>& other);
...
};
以上代码的意思是,对任何类型T和任何类型U,可以根据SmartPrt<U>
生成一个SmartPtr<T>
这个叫做泛化复制构造函数.
完成声明之后,我们需要提供更多的东西,因为我们希望根据一个SmartPtr<Bottom>
创建一个SmartPtr<Top>
,却不需要根据一个SmartPtr<Top>
创建一个SmartPtr<Top>
以stl的智能指针为榜样,我们可以这样写:
template<typename T>
class SmartPrt
{
public:
template<typename U>
SmartPrt(const SmartPtr<U> & other): heldPtr(other.get()){...}
T* get() const {return heldPtr;}
...
private:
T * heldPtr;
};
使用成员初始化列表来初始化SmartPrt<T>
之内类型为T的成员变了,并以类型为U的指针作为初值,这个行为只有当存在某个隐式转换可以将一个U指针转换为一个T指针时才能通过编译,这正是我们想要的.
成员函数模板还可以用于赋值操作。
总结:
1.使用成员函数模板生成可接受所有兼容类型的函数.
2.如果你声明成员模板用于泛化复制构造或泛化赋值操作,你还需要声明正常的复制构造函数和copy assignment操作符