讀書筆記_Effective_C++_條款四十五:運用成員函數模板接受全部兼容類型

好比有一個Base類和一個Derived類,像下面這樣:函數

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

由於是父類與子類的關係,因此能夠這樣寫:spa

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>的轉換並不存在,因此編譯器報錯。code

爲了能使這樣的轉換合法,咱們須要在原來的基礎上這樣寫:對象

 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轉換的類要有繼承關係。代碼還有賦值運算符也須要提供一個非泛化的版本和泛化的版本,這裏簡略沒有寫出。blog

 

這裏還有一個須要注意的地方,在class類聲明泛化copy構造函數(member template),並不會阻止編譯器生成它們本身的copy構造函數(non-template),換言之,若是程序中只寫了泛化的copy構造函數,那麼編譯器仍是會自動生成一個非泛化的版本出來,若是不想要這個缺省版本,那必定不能偷懶,要兩個版本的copy構造函數都要寫。繼承

 

最後總結一下:ci

1. 請使用member function templates(成員函數模板)生成「可接受全部兼容類型」的函數;element

2. 若是你聲明member templates用於「泛化copy構造」或「泛化assignment操做」,你仍是須要聲明正常的copy構造函數和copy assignment操做符。get

 

下面附上微軟對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 };
相關文章
相關標籤/搜索