成員函數模板是類別模板中的一種特殊成員,允許成員函數本身成為模板。它在 STL 中廣泛應用(如 auto_ptr、shared_ptr 的隱含轉換構造函數),但較少在一般業務程式碼中直接編寫。理解它對掌握智能指標、型別擦除、泛型程式設計至關重要。
假設類別繼承體系:MusicProduct 為基類,CD、MP3 繼承自它。我們定義一個簡易智能指標 SmartPtr<T>:
template <class T>
class SmartPtr {
public:
explicit SmartPtr(T* realPtr = nullptr) : pointee(realPtr) {}
T* operator->() const { return pointee; }
T& operator*() const { return *pointee; }
private:
T* pointee;
};
問題:若擁有 SmartPtr<CD>,能否隱含轉換為 SmartPtr<MusicProduct>?普通構造函數無法實現,因為 SmartPtr<MusicProduct> 的構造函數接受 MusicProduct*,而非 SmartPtr<CD>。這時需要成員函數模板構造函數:
template <class T>
class SmartPtr {
public:
explicit SmartPtr(T* realPtr = nullptr) : pointee(realPtr) {}
// 成員函數模板:允許從 SmartPtr<U> 隱含轉換,前提是 U* 可轉換為 T*
template <class U>
SmartPtr(const SmartPtr<U>& other) : pointee(other.pointee) {}
T* operator->() const { return pointee; }
T& operator*() const { return *pointee; }
private:
T* pointee;
};
U 與類別模板參數 T 完全獨立,編譯器根據實參推導 U。pointee(other.pointee) 要求 U* 隱含轉換為 T*,這正是繼承體系中向上轉型的語義。shared_ptr 的別名構造函數現代 C++ std::shared_ptr 更進一步,提供別名構造函數(aliasing constructor):
template <class Y>
shared_ptr(const shared_ptr<Y>& r, T* p) noexcept; // 共享所有權,但儲存不同指標
這同樣是成員函數模板的應用,允許智能指標管理子物件同時共享父物件的控制塊。
explicit 謹慎:轉換構造函數通常不加 explicit 以支援隱含轉換,但需權衡型別安全。enable_if 限制:C++11 可用 std::enable_if_t<std::is_convertible_v<U*, T*>> 限制模板實例化條件,提升錯誤訊息可讀性。this 指標型別:成員模板內 this 的型別是 SmartPtr<T>*,而非 SmartPtr<U>*。成員函數模板是 C++ 泛型程式設計的利器,掌握其語法、推導規則與典型應用場景,能讓你設計出更靈活、型別安全的庫級元件。