Effective C++ 条款45 运用成员函数模板接受所有兼容类型

1. "智能指针"是行为像指针的对象,但它们能提供指针没有的功能:shared_ptr,weak_ptr,auto_ptr(见条款13)实现对堆内存的自动管理,STL的迭代器实现对整个容器的遍历等.

    C++内置类型指针(int*,char*等)的优势在于支持继承层次中派生类指针向基类指针的转换(当然标准库shared_ptr,weak_ptr,auto_ptr等已实现).

2. 由于同一template的不同实例化之间没有直接联系,也就是说对于自定义的智能指针(假设名为SmartPtr),如果不额外采取手段支持基层层次中派生类指针向基类指针的转换,那么SmartPtr<Base>和SmartPtr<Derived>将会被编译器认为毫无关联,也就不存在SmartPtr<Derived>向SmartPtr<Base>的隐式转换.

    要获得Smart classes之间的隐式转换能力,就要明确地写出用于隐式转换的构造函数.

    假设存在一个Base类,要实现由SmartPtr<Base的派生类>向SmartPtr<Base>的转换,显然无法为SmartPtr写出所有用于隐式类型转换的copy构造函数,因为Base的继承体系的扩充可能性是无限的.因此只能采用成员函数模板做到一劳永逸:

template<typename T>
class SmartPtr{
public:
    template<typename U>
    SmartPtr(const SmartPtr<U>& other);  //生成copy构造函数用于隐式转换
    ....
}
View Code

    以上代码SmartPtr的copy构造函数的含义是对于任何类型U和类型T,都可以根据类型Smart<U>生成一个Smart<T>,因为SmartPtr<U>和SmartPtr<T>是同一template的不同实例化,因此这种构造函数被称为泛化copy构造函数.SmartPtr的泛化copy构造函数并没有被声明为explict,是为了模仿原始指针之间的隐式转换.

    以上copy构造函数的声明并无法将SmartPtr之间的转换局限在可转换的原始指针之间,因此要在SmartPtr实现中SmartPtr之间的转换进行限制,假设SmartPtr像auto_ptr一样提供了用于获取原始指针的get函数,那么SmartPtr(const SmartPtr<U>& other)的实现可能像这样:

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

    这样就把检查底层指针能否转换的任务交由底层指针来自行检查.

3. 成员模板函数(member template function)的效用并不局限于构造函数,它们的另一个常见作用是支持赋值操作.tr1的shared_ptr支持所有兼容的内置指针,tr1::shared_ptrs,auto_ptrs和weak_ptrs"的构造行为,以及所有来自上述物(除weak_ptr)的的赋值操作,以下是摘自TR1规范中关于tr1::shared_ptr的一份摘录:

template<typename T>
class shared_ptr{
public:
    template<class Y>    //声明类型参数时class和typename含义相同
        explict shared_ptr(Y* p);
    template<class Y>
        shared_ptr(shared_ptr<Y> const& r);
    template<class Y>
        explict shared_ptr(weak_ptr<Y> const& r);
    template<class Y>
        explict shared_ptr(auto_ptr<Y> const& r);
    template<class Y>
        shared_ptr& operator=(shared_ptr<Y> const& r);
    template<class Y>
        shared_ptr& operator=(auto_ptr<Y> const& r);
    ...
}
View Code

    以上所有构造函数都为explict,唯有泛化copy构造函数除外,这意味着shared_ptr允许shared_ptr之间的隐式类型转换,而禁止原始指针或其他智能指针类型向shared_ptr的转换;此外,传递给tr1::shared_ptr构造函数和赋值操作符的auto_ptr并未被声明const,因为auto_ptr在这之后会被置为NULL.

4. 需要注意的是,虽然成员函数模板(member function template)可以实例化出用于shared_ptr<T>向shared_ptr<T>转换的copy构造函数,但如果没有声明copy构造函数,编译器还是会合成一个,所以不能依赖于成员函数模板的实例化,要手动声明一个普通的copy构造函数.copy赋值操作符也是一样.

原文地址:https://www.cnblogs.com/reasno/p/4802034.html