如何实现支持继承特性的自定义C++ SmartPointer类
自定义智能指针的继承适配实现方案
需求概述
需要实现一款自定义SmartPointer类,核心目标是让原类的继承关系能传递到对应的智能指针类型:若Parent类被ChildA、ChildB继承,那么生成的智能指针Parentsp、ChildAsp、ChildBsp需要支持继承适配——参数为Parentsp的函数可以接受ChildAsp或ChildBsp类型传入。
现有实现代码
当前的引用计数器和智能指针实现如下:
class RefCounter { public: void AddRef() {count++;} int Release() {return --count;} private: int count; // 未初始化,存在bug }; template<typename T> class SmartPointer { public: SmartPointer() : mPtr(nullptr), mRef(nullptr) { mRef = new RefCounter(); mRef->AddRef(); } SmartPointer(T* mPtr) : mPtr(mPtr), mRef(nullptr) { mRef = new RefCounter(); mRef->AddRef(); } SmartPointer(const SmartPointer<T>& other) : mPtr(other.mPtr), mRef(other.mRef){ mRef->AddRef(); } ~SmartPointer(){ if(mRef->Release() == 0) { delete mPtr; delete mRef; } } T& ptr(){ return *mPtr; } T& operator*(){ return *mPtr; } T* operator->(){ return mPtr; } SmartPointer<T>& operator=(const SmartPointer<T>& other) { if (this != &other) { if(mRef->Release() == 0) { delete mPtr; delete mRef; } mPtr = other.mPtr; mRef = other.mRef; mRef->AddRef(); } return *this; } private: T* mPtr; RefCounter* mRef; };
尝试的失败代码
曾尝试修改MAKE_SP宏让智能指针继承,但无法正常运行:
#define MAKE_SP(cls) SmartPointer<cls> cls##sp /* 错误的尝试 */ class Parent; MAKE_SP(Parent); class Parent { ... } class ChildA; MAKE_SP(ChildA); class ChildA : public Parent { ... } class ChildB; MAKE_SP(ChildB); class ChildB : public Parent { ... } void sp_func(Parentsp parent) { ... } main() { ChildAsp c1 = new ChildAsp; sp_func(c1); ChildBsp c2 = new ChildBsp; sp_func(c2); }
可行解决方案
核心思路是给SmartPointer添加模板转换构造函数和模板赋值运算符,允许子类智能指针隐式转换为父类智能指针,同时保留MAKE_SP宏的typedef方式。
1. 修复引用计数器的初始化bug
首先修正RefCounter的未初始化问题:
class RefCounter { public: RefCounter() : count(0) {} // 初始化计数为0 void AddRef() { count++; } int Release() { return --count; } private: int count; };
2. 修改SmartPointer类,添加转换支持
#include <type_traits> // 用于static_assert做编译期检查 template<typename T> class SmartPointer { public: // 默认构造函数 SmartPointer() : mPtr(nullptr), mRef(new RefCounter()) { mRef->AddRef(); } // 原始指针构造(explicit避免隐式转换) explicit SmartPointer(T* ptr) : mPtr(ptr), mRef(new RefCounter()) { mRef->AddRef(); } // 同类型拷贝构造 SmartPointer(const SmartPointer<T>& other) : mPtr(other.mPtr), mRef(other.mRef) { mRef->AddRef(); } // 模板转换构造函数:支持子类智能指针转换为父类智能指针 template<typename U> SmartPointer(const SmartPointer<U>& other) : mPtr(other.mPtr), mRef(other.mRef) { // 编译期验证U可转换为T static_assert(std::is_convertible_v<U*, T*>, "类型U无法转换为T"); mRef->AddRef(); } ~SmartPointer() { cleanup(); } T& ptr() { return *mPtr; } const T& ptr() const { return *mPtr; } T& operator*() { return *mPtr; } const T& operator*() const { return *mPtr; } T* operator->() { return mPtr; } const T* operator->() const { return mPtr; } // 同类型赋值运算符 SmartPointer<T>& operator=(const SmartPointer<T>& other) { if (this != &other) { cleanup(); mPtr = other.mPtr; mRef = other.mRef; mRef->AddRef(); } return *this; } // 模板赋值运算符:支持子类智能指针赋值给父类智能指针 template<typename U> SmartPointer<T>& operator=(const SmartPointer<U>& other) { static_assert(std::is_convertible_v<U*, T*>, "类型U无法转换为T"); // 避免跨类型的自我赋值 if (this != reinterpret_cast<const SmartPointer<T>*>(&other)) { cleanup(); mPtr = other.mPtr; mRef = other.mRef; mRef->AddRef(); } return *this; } private: // 提取清理逻辑,复用代码 void cleanup() { if (mRef->Release() == 0) { delete mPtr; delete mRef; } } T* mPtr; RefCounter* mRef; // 允许其他SmartPointer模板实例访问私有成员 template<typename U> friend class SmartPointer; };
3. 保留MAKE_SP宏
继续使用typedef方式生成智能指针类型:
#define MAKE_SP(cls) typedef SmartPointer<cls> cls##sp
4. 测试代码
#include <iostream> class Parent { public: virtual ~Parent() = default; // 基类必须加虚析构,确保子类析构正确调用 virtual void say() const { std::cout << "Parent" << std::endl; } }; MAKE_SP(Parent); class ChildA : public Parent { public: void say() const override { std::cout << "ChildA" << std::endl; } }; MAKE_SP(ChildA); class ChildB : public Parent { public: void say() const override { std::cout << "ChildB" << std::endl; } }; MAKE_SP(ChildB); void sp_func(Parentsp parent) { parent->say(); } int main() { ChildAsp c1(new ChildA()); sp_func(c1); // 子类智能指针隐式转换为父类智能指针 ChildBsp c2(new ChildB()); sp_func(c2); // 测试赋值 Parentsp p = c1; p->say(); return 0; }
关键说明
- 模板转换构造/赋值:通过
template<typename U>实现跨类型转换,配合std::is_convertible_v做编译期检查,确保只有合法的继承关系才能转换。 - 友元声明:让不同模板实例的
SmartPointer可以互相访问私有成员,保证转换时能正确获取指针和引用计数器。 - 虚析构函数:基类
Parent必须添加虚析构,否则通过Parentsp删除ChildA对象时,只会调用父类析构函数,导致子类资源泄漏。 - explicit构造:原始指针构造函数加
explicit,避免意外的隐式转换,提升代码安全性。
内容的提问来源于stack exchange,提问作者Sam Kent
相关产品推荐
相关产品推荐

