Effective C++ 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 *pct2 = pt1; //将Top*转换为const Top*

但是在自定的模板(这里拿只能指针来举例)上模拟上述转换,就遇到了麻烦,我们希望能够这样:

<pre name="code" class="cpp"><pre name="code" class="cpp">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<const Top> pct2 = pt1;

以上代码是不能通过编译的,因为以带有继承关系的两种类型分别具现化某个模板类,产生出来的两个具现体并不带有继承关系。那怎么办呢?
 
</pre><pre name="code" class="cpp">实现:我们容易想到既然具现体不同,那么就把具现体当做模板形参来使用,很容易想到实现该智能指针的copy构造函数为函数模板:
 
 
template<typename T>
class SmartPtr
{
public:
    template<typename U>
    SmartPtr(const SmartPtr<U> &other);
    ...
};

上面的构造函数为模板,解释:根据对象SmartPtr<U>创建对象SmartPtr<T>,而它们是同一个template的不同具现体,有时我们称之为泛化(generalized)copy构造函数。
 
</pre><pre name="code" class="cpp">但是,这样就行了吗?如果我想以SmartPtr<Top>创建一个SmartPtr<Bottom>的话,那对继承体系来说是不合理的,反过来才合理,那么怎么实现该模板就成为关键,最终我们找到了好的方法,把问题丢给编译器:
template<typename T>
class SmartPtr
{
public:
    template<typename U>
    SmartPtr(const SmartPtr<U>& other)
        : heldPtr(other.get()){}//以原始指针初始化
    T *get() const {return heldPtr;}
    ...
private:
    T *heldPtr;//原始指针
};

上面使用原始指针初始化,这样不符合继承体系的copy时编译器就会有所回应了,解决了后顾之忧。
 
</pre><pre name="code" class="cpp">现实中的shared_ptr是怎样实现的呢?
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);//兼容shared_ptr
    template<class Y>
    explicit shared_ptr(weak_ptr<Y> const &r);//兼容weak_ptr
    template<class Y>
    explicit shared_ptr(auto_ptr<Y> &r);//兼容auto_ptr
    template<class Y>
    shared_ptr & operator=(shared_ptr<Y> const &r);
    template<class Y>
    shared_ptr & operator=(auto_ptr<Y>  &r);//赋值,兼容shared_ptr和auto_ptr
    ...
};

上述代码的细节分析,除了泛化的copy构造函数除外,剩下的构造函数都是explicit的,那意味着,shared_ptr类型隐式转化为一个shared_ptr是允许的,另一点是,以auto_ptr为参数的构造函数和赋值操作符未声明为const,因为,当你复制一个auto_ptr时,它们其实已经改动了。
 
</pre><pre name="code" class="cpp">最后,成员模板并不改变语言规则,编译器还是会生成自己的构造函数和赋值函数,所以现实中的版本,你还是要声明正常的copy构造函数和赋值操作符。
</pre><pre name="code" class="cpp">总结:请使用member function templates(成员函数模板)生成“可接受所有兼容类型”的函数。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值