首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

Effective C++ 條款 45:成員函式模板——支援智慧型指標的隱式轉換

     編輯:關於C++

問題:智慧型指標缺乏內建指標的隱式轉換

內建指標天然支援衍生類指標→基類指標、T*→const T* 等隱式轉換:


class Top {}; class Middle : public Top {}; class Bottom : public Middle {};
Top* pt1 = new Middle;        // Middle* → Top*
const Top* pct2 = pt1;        // Top* → const Top*

若智慧型指標 SmartPtr<T> 要模仿此行為,SmartPtr<Middle> 應能隱式轉為 SmartPtr<Top>。但模板不同實例化間無繼承關係,編譯器視為完全無關型別。

解決方案:泛化拷貝建構函式

使用成員函式模板 (Member Function Template) 接受所有相容型別:


template<typename T>
class SmartPtr {
public:
    explicit SmartPtr(T* realPtr);
    template<typename U>           // 成員模板
    SmartPtr(const SmartPtr<U>& other); // 泛化拷貝建構函式
    // ...
};

此模板對每個 U 產生一個建構函式,使 SmartPtr<T> 可從任意 SmartPtr<U> 建構。為模仿內建指標隱式轉換,刻意不加 explicit。

限制轉換方向:利用內建指標轉換規則

若 SmartPtr 提供 get() 回傳持有指標,建構函式可透過成員初始化列表嘗試轉換:


template<typename T>
class SmartPtr {
public:
    template<typename U>
    SmartPtr(const SmartPtr<U>& other)
        : heldPtr(other.get()) { }  // 僅當 U* 隱式轉換為 T* 合法時編譯通過
    T* get() const { return heldPtr; }
private:
    T* heldPtr;
};

編譯器會檢查 U* → T* 的隱式轉換是否合法:

  • SmartPtr<Middle> → SmartPtr<Top> ✓ (公有繼承)
  • SmartPtr<Top> → SmartPtr<Bottom> ✗ (違反 is-a)
  • SmartPtr<double> → SmartPtr<int> ✗ (無標準轉換)

完美模仿內建指標語意!

擴展至指派運算子與多來源建構

TR1 shared_ptr 示範完整用法:


template<class T> class shared_ptr {
public:
    template<class Y> explicit shared_ptr(Y* p);
    template<class Y> shared_ptr(shared_ptr<Y> const& r);
    template<class Y> explicit shared_ptr(weak_ptr<Y> const& r);
    template<class Y> explicit shared_ptr(auto_ptr<Y>& r);
    template<class Y> shared_ptr& operator=(shared_ptr<Y> const& r);
    template<class Y> shared_ptr& operator=(auto_ptr<Y>& r);
    // ...
};
  • 泛化拷貝建構/指派 非 explicit,允許智慧型指標間隱式轉換。
  • 從內建指標、weak_ptr、auto_ptr 建構 explicit,禁止隱式轉換。
  • auto_ptr 參數非 const,因其複製語意會修改來源 (所有權轉移)。

陷阱:成員模板不阻擋編譯器產生預設拷貝/指派

當 T == U 時,泛化建構函式可實例化為一般拷貝建構函式。但編譯器仍會自動產生非模板版本的拷貝建構函式與指派運算子。若想完全控制,必須額外宣告一般版本:


template<class T> class shared_ptr {
public:
    shared_ptr(shared_ptr const& r);           // 一般拷貝建構
    template<class Y> shared_ptr(shared_ptr<Y> const& r); // 泛化
    shared_ptr& operator=(shared_ptr const& r); // 一般指派
    template<class Y> shared_ptr& operator=(shared_ptr<Y> const& r); // 泛化
    // ...
};

核心心法

  • 成員函式模板生成接受所有相容型別的函式,實現泛化建構/指派。
  • 宣告泛化版本不免除宣告一般拷貝建構函式與指派運算子的責任。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved