Effective_C++_条款四十五:运用成员函数模板接受所有兼容类型

Effective_C++_条款四十五:运用成员函数模板接受所有兼容类型

首先理解标题的含义

真实指针是支持隐式转换的,智能指针是行为像指针的对象,并且提供指针没有的机能。现在我们想如何编写智能指针的构造函数,使其行为能够满足我们的转型需求。因为一个template可以无限量具现化,所以我们无法写出我们需要的所有构造函数,我们解决问题的方法是不是为智能指针写一个构造函数,而是直接为其写一个构造模板。

template<typename T>
class SmartPtr{
 	public:
 	template<typename U>                     //成员函数模板
 	SmartPtr(const SmartPtr<U>& other);    //为了生存copy构造函数
}

因为要根据现实中继承的意义完成转换,所以我们必须从某方面对这一member template所创建的成员函数群进行拣选或筛除。

举个例子:

比如有一个Base类和一个Derived类,像下面这样:

1 class BaseClass
2 {…};
3 
4 class DerivedClass : public BaseClass
5 {…};

因为是父类与子类的关系,所以可以这样写:

1 DerivedClass *d;
2 BaseClass *b = static_cast< BaseClass *>d; // 用C风格直接是 b = (BaseClass*) d;

我们可以弄一个简易的Shared型智能指针类,如果直接像下面这样写:

template <class T>
class SharedPtr
{
private:
    T* Ptr;
    static size_t Count;
    
public:
    SharedPtr(T* _ptr)
    {
        Count = 1;
        Ptr = _ptr;
        cout << "Constructor Called Same" << endl;
    }
    ~SharedPtr()
    {
        cout << "Destructor Called" << endl;
        if (--Count == 0)
        {
            cout << "Delete Pointer" << endl;
            delete Ptr;
            Ptr = NULL;
        }
    }
    SharedPtr(const SharedPtr<T>& _Smart)
    {
        cout << "Copy Constructor Called Same" << endl;
        Ptr = _Smart.Ptr;
        ++Count;
    }
};

那么显示编译器不会允许SharedPtr pb(pd),因为在编译期替换T时,拷贝构造函数明确了接受类型必须是SharedPtr,而由SharedPtr对象至SharedPtr的转换并不存在,所以编译器报错。

为了能使这样的转换合法,我们需要在原来的基础上这样写:

class SharedPtr
{
private:
    T* Ptr;
    static size_t Count;
 
public:
    SharedPtr(T* _ptr)
    {
        Count = 1;
        Ptr = _ptr;
        cout << "Constructor Called Same" << endl;
    }
 
    template <class Other>
    SharedPtr(Other* _ptr)
    {
        Count = 1;
        Ptr = static_cast<T*> (_ptr);
        cout << "Constructor Called Other" << endl;
    }
 
    ~SharedPtr()
    {
        cout << "Destructor Called" << endl;
        if (--Count == 0)
        {
            cout << "Delete Pointer" << endl;
            delete Ptr;
            Ptr = NULL;
        }
    }
 
    T* GetPointer()
    {
        return Ptr;
    }
 
    T* GetPointer() const
    {
        return Ptr;
    }
 
    SharedPtr(const SharedPtr<T>& _Smart)
    {
        cout << "Copy Constructor Called Same" << endl;
        Ptr = _Smart.Ptr;
        ++Count;
    }
 
 
    template <class Other>
    SharedPtr(const SharedPtr<Other>& _Smart)
    {
        cout << "Copy Constructor Called Other" << endl;
        Ptr = static_cast<T*>(_Smart.GetPointer());
        ++Count;
    }
};

这里另外声明了一个模板参数Other,它可以与T相同,也可以不同,也就意味着它可以接受任何可以转化成T的类型了,比如父子类。这里还定义了GetPointer的方法,因为拷贝构建中传入的对象不一定是属于同一个类的,所以不能保证可以访问到类的私有成员。Ptr = static_cast<T*>(_Smart.GetPointer())这句话其实就是转换的实质了,只要任何可以转成T的Other,都是可以通过编译的,但如果是风马牛不相及的两个类,就不会通过编译。这里有一点要强调一下,我们可以把double转成int(窄化),也可以把int转成double(宽化),但注意double与int之间是不能相互转的,如果这样写int a = (int) (new double(2)),是不能通过编译的,可以用static_cast转换的类要有继承关系。代码还有赋值运算符也需要提供一个非泛化的版本和泛化的版本,这里简略没有写出。

这里还有一个需要注意的地方,在class类声明泛化copy构造函数(member template),并不会阻止编译器生成它们自己的copy构造函数(non-template),换言之,如果程序中只写了泛化的copy构造函数,那么编译器还是会自动生成一个非泛化的版本出来,如果不想要这个缺省版本,那一定不能偷懒,要两个版本的copy构造函数都要写。

最后总结一下:

1. 请使用member function templates(成员函数模板)生成“可接受所有兼容类型”的函数;

2. 如果你声明member templates用于“泛化copy构造”或“泛化assignment操作”,你还是需要声明正常的copy构造函数和copy assignment操作符。

下面附上微软对shared_ptr类的声

template<class Ty>
   class shared_ptr {
public:
    typedef Ty element_type;
    shared_ptr();
    shared_ptr(nullptr_t); 
    shared_ptr(const shared_ptr& sp);
    shared_ptr(shared_ptr&& sp);
    template<class Other>
        explicit shared_ptr(Other * ptr);
    template<class Other, class D>
     shared_ptr(Other * ptr, D dtor);
    template<class D>
        shared_ptr(nullptr_t, D dtor);
    template<class Other, class D, class A>
        shared_ptr(Other *ptr, D dtor, A alloc);
    template<class D, class A>
        shared_ptr(nullptr_t, D dtor, A alloc);
    template<class Other>
        shared_ptr(const shared_ptr<Other>& sp);
    template<class Other>
        shared_ptr(const shared_ptr<Other>&& sp);
    template<class Other>
        explicit shared_ptr(const weak_ptr<Other>& wp);
    template<class Other>
        shared_ptr(auto_ptr<Other>& ap);
    template<class Other, class D>
        shared_ptr(unique_ptr<Other, D>&& up);
    template<class Other>
        shared_ptr(const shared_ptr<Other>& sp, Ty *ptr);
    ~shared_ptr();
    shared_ptr& operator=(const shared_ptr& sp);
    template<class Other> 
        shared_ptr& operator=(const shared_ptr<Other>& sp);
    shared_ptr& operator=(shared_ptr&& sp);
    template<class Other> 
        shared_ptr& operator=(shared_ptr<Other>&& sp);
    template<class Other> 
        shared_ptr& operator=(auto_ptr< Other >&& ap);
    template <class Other, class D> 
        shared_ptr& operator=(const unique_ptr< Other, D>& up) = delete;
    template <class Other, class D>
        shared_ptr& operator=(unique_ptr<Other, D>&& up);
    void swap(shared_ptr& sp);
    void reset();
    template<class Other>
        void reset(Other *ptr);
    template<class Other, class D>
        void reset(Other *ptr, D dtor);
    template<class Other, class D, class A>
        void reset(Other *ptr, D dtor, A alloc);
    Ty *get() const;
    Ty& operator*() const;
    Ty *operator->() const;
    long use_count() const;
    bool unique() const;
    operator bool() const;
    template<class Other>
        bool owner_before(shared_ptr<Other> const& ptr) const;
    template<class Other>
        bool owner_before(weak_ptr<Other> const& ptr) const;
    template<class D, class Ty> 
        D* get_deleter(shared_ptr<Ty> const& ptr);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值