You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现支持继承特性的自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 23:14:53