Item 45: 利用成员函数模板接受所有兼容类型(智能指针的部分实现)

真实指针做得很好的一件事是,它支持隐式转换,如下:

    class Top { ... };
    class Middle: public Top{ ... };
    class Bottom: public Middle { ... };
    Top* pt1 = new Middle;      //将Middle*转换为Top*
    Middle* pt2 = new Bottom;   //将Bottom*转换为Middle*
    const Top* pct2 = pt1;      //将Top*转换为const Top*

我们希望智能指针也能实现像真实指针这样的自动转换,即我们可以像下面那样转换智能指针:

    template<typename T>
    class SmartPtr{
      public:
        explicit SmartPtr( T* realPtr );    //以内置指针完成初始化
        ...
    };
    SmartPtr<Top> pt1 = SmartPtr<Middle>( new Middle ); //将SmartPtr<Middle>转换为SmartPtr<Top>
    SmartPtr<Top> pt2 = SmartPtr<Bottom>( new Bottom ); //将SmartPtr<Bottom>转换为SmartPtr<Top>
    SmartPtr<const Top> pct2 = pt1;             //将SmartPtr<Top>转换耿SmartPtr<const Top>

为此我们可以为SmartPtr编写构造函数,使其行为能够满足我们的转型需要。可是似乎我们无法写出我们需要的所有构造函数,因为一旦一个继承体系被扩充,相当于我们需要添加一个构造函数。我们必须为它写一个构造模板。这样的模板是所谓member function template(成员函数模板),其作用是为class生成函数:

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

这段代码的意思是,对任何类型T和任何类型U,这里可以根据SmartPtr生成一个SmartPtr。这样的函数我们称之为泛化copy构造函数。
但是,我们并不希望根据一个SmartPtr生成一个SmartPtr,这不符合逻辑。我们可以在“构造模板”实现代码中约束转换行为:

template<typename T>
class SmartPtr{
  public:
    //这样如果两者不兼容,不支持隐式转换,编译会报错。
    template<typename T>
      SmartPtr( const SmartPtr<U>& other )
      : heldPtr(other.get()){   }
    T* get() const{ return heldPtr; }
  private:
    T* heldPtr;
      ...
};

member function template的效用不限于构造函数,它们常扮演的另一个角色是支持赋值操作。另外,member function template并不改变语言基本规则。如果程序需要一个copy构造函数,而你没有声明它,编译器会为你暗自生成一个。在class内声明泛化copy构造函数并不会阻止编译器生成它们自己的copy构造函数(non-template的)。因此如果你想要控制copy构造函数的方方面面,你必须同时声明泛化构造函数和“正常的”copy构造函数。相同规则也适用于赋值操作。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值