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

shared_ptr向纯虚基类的拷贝转换机制及实例场景解析

关于shared_ptr向上转型与纯虚基类的处理逻辑

核心问题拆解

你提到的场景里有两个关键疑问,咱们逐个说清楚:


1. shared_ptr如何完成从A到IError的转换?

std::shared_ptr本身支持隐式向上转型,只要派生类(A)是基类(IError)的可访问派生类(这里是public继承,完全符合要求)。

这个转换依赖于shared_ptr的模板构造函数,而非普通的类型强制转换。标准库中shared_ptr提供了这样的模板构造:

template<class Y>
shared_ptr(const shared_ptr<Y>& r) noexcept;

当你把shared_ptr<A>传给需要shared_ptr<IError>的B构造函数时,编译器会自动匹配这个模板构造函数,检查A*是否能隐式转换为IError*(因为A继承自IError,这个转换合法),然后创建一个指向同一个对象的shared_ptr<IError>实例。


2. 这是不是普通的拷贝构造调用?

不是。

普通的shared_ptr拷贝构造函数是针对同类型的:

shared_ptr(const shared_ptr& r) noexcept;

而咱们场景中是从shared_ptr<A>转成shared_ptr<IError>,属于不同类型之间的构造,调用的是上面提到的模板构造函数。

不过要注意:不管是拷贝构造还是模板构造,最终的效果都是共享同一个控制块,引用计数会正常增加。比如你的代码里:

  • objA创建时,引用计数是1;
  • 传给B的构造函数后,mErrorReporter(shared_ptr<IError>)和objA共享同一个控制块,引用计数变成2;
  • 当objA和objB都被销毁时,引用计数降到0,才会释放A的实例。

纯虚基类IError的影响?

IError是纯虚基类这件事,对shared_ptr的转换逻辑没有任何特殊影响。纯虚只是限制了不能直接实例化IError,但shared_ptr<IError>完全可以指向它的派生类实例(比如A),这和普通非纯虚基类的情况完全一致。

你的示例代码能正常运行,就是因为shared_ptr<IError>可以通过模板构造函数从shared_ptr<A>隐式转换而来,然后调用OnError()时,通过多态调用A的实现。


修正后的示例代码

#include <iostream>
#include <string>
#include <memory>  // 原代码遗漏了shared_ptr依赖的头文件

class IError 
{    
    public:
        virtual ~IError(){};
        virtual void OnError() = 0;
};

class A : public IError 
{
    public:
       A(){};
       void OnError(){std::cout << "Error Occured" << std::endl;} 
};

class B
{
  public:
     B(std::shared_ptr<IError> errorReporter): mErrorReporter(errorReporter){}
     void Action(){mErrorReporter->OnError();}

  private:   
     std::shared_ptr<IError> mErrorReporter;
};

int main()
{
    auto objA = std::make_shared<A>();
    auto objB = std::make_shared<B>(objA);
    objB->Action();
}

内容的提问来源于stack exchange,提问作者TruckerCat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 06:22:06