內建指標天然支援衍生類指標→基類指標、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);
// ...
};
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); // 泛化
// ...
};