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

基类含unique_ptr时,引用类型dynamic_cast为何编译失败?

问题分析:dynamic_cast引用版编译失败的原因与解决办法

问题场景

基类包含接收基类引用的纯虚函数(用于拷贝逻辑),派生类中尝试将该引用转为派生类类型,原本正常;但在基类添加Base类型的unique_ptr成员后,引用类型的dynamic_cast编译失败,改用指针类型则正常。注释掉unique_ptr成员或引用转换的代码时,程序可正常编译运行。

示例代码

#include <memory>
#include <iostream>

class Base {
public:
    Base() {}
    void hello() const { std::cout << "hello world" << std::endl; }
protected:
    virtual void cvt( Base& ) const = 0;
    std::unique_ptr<Base> any_member_unique_ptr;                    // "A"
};

class Derived : public Base {
public:
    Derived() { std::cout << "new Derived" << std::endl; }
    void cvt( Base& in ) const override {
        const auto cast_fail = dynamic_cast<const Derived&>( in );  // "B"
        const auto cast_okay = dynamic_cast<const Derived*>( &in );
        hello();
    }
};

int main(int argc, char *argv[])
{
    Derived D, P;
    D.cvt( P );
}

编译错误信息

tt.cpp: In member function ‘virtual void Derived::cvt(Base&) const’:
tt.cpp:17:69: error: use of deleted function ‘Derived::Derived(const Derived&)’
   17 |      const auto cast_fail = dynamic_cast<const Derived&>( in );  // "B"
      |                                                              ^

tt.cpp:13:7: note: ‘Derived::Derived(const Derived&)’ is implicitly deleted because the default definition would be ill-formed:
   13 | class Derived : public Base {
      |       ^~~~~~~
tt.cpp:13:7: error: use of deleted function ‘Base::Base(const Base&)’
tt.cpp:4:7: note: ‘Base::Base(const Base&)’ is implicitly deleted because the default definition would be ill-formed:
    4 | class Base {
      |       ^~~~
tt.cpp:4:7: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Base; _Dp = std::default_delete<Base>]’
In file included from /usr/include/c++/11/memory:76,
                 from tt.cpp:1:
/usr/include/c++/11/bits/unique_ptr.h:468:7: note: declared here
  468 |       unique_ptr(const unique_ptr&) = delete;
      |       ^~~~~~~~~~
make: *** [<builtin>: tt] Error 1

原因解析

  1. 引用转换的隐式拷贝陷阱:dynamic_cast<const Derived&>(in)返回的是引用,但你写的const auto cast_fail = ...中,auto会推导为const Derived(值类型),这意味着代码试图用转换后的引用拷贝构造一个新的Derived对象。
  2. 拷贝构造被删除的连锁反应:基类中的std::unique_ptr<Base>成员的拷贝构造函数是被显式删除的,因此基类的默认拷贝构造函数会被隐式删除;派生类继承了这一特性,其默认拷贝构造函数也会被隐式删除。当代码尝试拷贝构造Derived对象时,就会触发编译错误。
  3. 指针转换无拷贝行为:指针版的dynamic_cast返回的是指针,const auto cast_okay推导为const Derived*,只是赋值指针地址,不需要拷贝构造对象,因此不会触发错误。

解决方案

将引用转换的结果声明为引用类型,避免触发拷贝构造:

// 方式1:显式声明引用类型
const Derived& cast_ok = dynamic_cast<const Derived&>(in);
// 方式2:用auto&推导引用类型
const auto& cast_ok = dynamic_cast<const Derived&>(in);

修改后,代码只是将引用绑定到原对象上,不会触发拷贝构造,即可正常编译运行。

内容的提问来源于stack exchange,提问作者rand'Chris

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 00:46:03