• 读书笔记_Effective_C++_条款四十五:运用成员函数模板接受所有兼容类型


    比如有一个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型智能指针类,如果直接像下面这样写:

     1 template <class T>
     2 class SharedPtr
     3 {
     4 private:
     5     T* Ptr;
     6     static size_t Count;
     7 
     8 public:
     9     SharedPtr(T* _ptr)
    10     {
    11         Count = 1;
    12         Ptr = _ptr;
    13         cout << "Constructor Called Same" << endl;
    14     }
    15     ~SharedPtr()
    16     {
    17         cout << "Destructor Called" << endl;
    18         if (--Count == 0)
    19         {
    20             cout << "Delete Pointer" << endl;
    21             delete Ptr;
    22             Ptr = NULL;
    23         }
    24     }
    25 
    26     SharedPtr(const SharedPtr<T>& _Smart)
    27     {
    28         cout << "Copy Constructor Called Same" << endl;
    29         Ptr = _Smart.Ptr;
    30         ++Count;
    31     }
    32 };

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

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

     1 class SharedPtr
     2 {
     3 private:
     4     T* Ptr;
     5     static size_t Count;
     6 
     7 public:
     8     SharedPtr(T* _ptr)
     9     {
    10         Count = 1;
    11         Ptr = _ptr;
    12         cout << "Constructor Called Same" << endl;
    13     }
    14 
    15     template <class Other>
    16     SharedPtr(Other* _ptr)
    17     {
    18         Count = 1;
    19         Ptr = static_cast<T*> (_ptr);
    20         cout << "Constructor Called Other" << endl;
    21     }
    22 
    23     ~SharedPtr()
    24     {
    25         cout << "Destructor Called" << endl;
    26         if (--Count == 0)
    27         {
    28             cout << "Delete Pointer" << endl;
    29             delete Ptr;
    30             Ptr = NULL;
    31         }
    32     }
    33 
    34     T* GetPointer()
    35     {
    36         return Ptr;
    37     }
    38 
    39     T* GetPointer() const
    40     {
    41         return Ptr;
    42     }
    43 
    44     SharedPtr(const SharedPtr<T>& _Smart)
    45     {
    46         cout << "Copy Constructor Called Same" << endl;
    47         Ptr = _Smart.Ptr;
    48         ++Count;
    49     }
    50 
    51 
    52     template <class Other>
    53     SharedPtr(const SharedPtr<Other>& _Smart)
    54     {
    55         cout << "Copy Constructor Called Other" << endl;
    56         Ptr = static_cast<T*>(_Smart.GetPointer());
    57         ++Count;
    58     }
    59 };

    注意代码标注为蓝色的部分(即为泛化部分),这里另外声明了一个模板参数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类的声明,对比黄色加亮部分,可以看到本条款所说的技术要点。

     1 template<class Ty>
     2    class shared_ptr {
     3 public:
     4     typedef Ty element_type;
     5 
     6     shared_ptr();
     7     shared_ptr(nullptr_t); 
     8     shared_ptr(const shared_ptr& sp);
     9     shared_ptr(shared_ptr&& sp);
    10     template<class Other>
    11         explicit shared_ptr(Other * ptr);
    12     template<class Other, class D>
    13         shared_ptr(Other * ptr, D dtor);
    14     template<class D>
    15         shared_ptr(nullptr_t, D dtor);
    16     template<class Other, class D, class A>
    17         shared_ptr(Other *ptr, D dtor, A alloc);
    18     template<class D, class A>
    19         shared_ptr(nullptr_t, D dtor, A alloc);
    20     template<class Other>
    21         shared_ptr(const shared_ptr<Other>& sp);
    22     template<class Other>
    23         shared_ptr(const shared_ptr<Other>&& sp);
    24     template<class Other>
    25         explicit shared_ptr(const weak_ptr<Other>& wp);
    26     template<class Other>
    27         shared_ptr(auto_ptr<Other>& ap);
    28     template<class Other, class D>
    29         shared_ptr(unique_ptr<Other, D>&& up);
    30     template<class Other>
    31         shared_ptr(const shared_ptr<Other>& sp, Ty *ptr);
    32     ~shared_ptr();
    33     shared_ptr& operator=(const shared_ptr& sp);
    34     template<class Other> 
    35         shared_ptr& operator=(const shared_ptr<Other>& sp);
    36     shared_ptr& operator=(shared_ptr&& sp);
    37     template<class Other> 
    38         shared_ptr& operator=(shared_ptr<Other>&& sp);
    39     template<class Other> 
    40         shared_ptr& operator=(auto_ptr< Other >&& ap);
    41     template <class Other, class D> 
    42         shared_ptr& operator=(const unique_ptr< Other, D>& up) = delete;
    43     template <class Other, class D>
    44         shared_ptr& operator=(unique_ptr<Other, D>&& up);
    45     void swap(shared_ptr& sp);
    46     void reset();
    47     template<class Other>
    48         void reset(Other *ptr);
    49     template<class Other, class D>
    50         void reset(Other *ptr, D dtor);
    51     template<class Other, class D, class A>
    52         void reset(Other *ptr, D dtor, A alloc);
    53     Ty *get() const;
    54     Ty& operator*() const;
    55     Ty *operator->() const;
    56     long use_count() const;
    57     bool unique() const;
    58     operator bool() const;
    59 
    60     template<class Other>
    61         bool owner_before(shared_ptr<Other> const& ptr) const;
    62     template<class Other>
    63         bool owner_before(weak_ptr<Other> const& ptr) const;
    64     template<class D, class Ty> 
    65         D* get_deleter(shared_ptr<Ty> const& ptr);
    66 };
  • 相关阅读:
    nginx配置
    线程与进程的区别:
    java面试题1
    递归的定义和优缺点
    使用jedis连接redis可能会出现的问题及解决方案
    Linux上安装Redis
    Linux 权限管理
    Maven
    网址备份
    反射
  • 原文地址:https://www.cnblogs.com/jerry19880126/p/3646432.html
Copyright © 2020-2023  润新知