为何非const的std::shared_ptr引用无法实现多态?
我在尝试用多态方式使用std::shared_ptr时遇到了一个问题:函数参数为const std::shared_ptr<A>&时可以正常运行,但参数为std::shared_ptr<A>&时会编译报错。以下是测试代码:
#include <iostream> #include <memory> class A { public: virtual void foo() { std::cout << "A" << std::endl; } }; class B : public A { public: void foo() override { std::cout << "B" << std::endl; } }; void working(const std::shared_ptr<A>& ptr) { ptr->foo(); } void not_working(std::shared_ptr<A>& ptr) { ptr->foo(); } int main() { auto ptr = std::make_shared<B>(); working(ptr); not_working(ptr); // <-- 编译错误 return 0; }
编译后得到的错误信息如下:
main.cpp: In function ‘int main()’: main.cpp:24:16: error: cannot bind non-const lvalue reference of type ‘std::shared_ptr<A>&’ to an rvalue of type ‘std::shared_ptr<A>’ 24 | not_working(ptr); | ^~~ In file included from /usr/include/c++/11/memory:77, from main.cpp:2: /usr/include/c++/11/bits/shared_ptr.h:296:9: note: after user-defined conversion: ‘std::shared_ptr<_Tp>::shared_ptr(const std::shared_ptr<_Yp>&) [with _Yp = B; <template-parameter-2-2> = void; _Tp = A]’ 296 | shared_ptr(const shared_ptr<_Yp>& __r) noexcept | ^~~~~~~~~~ main.cpp:18:37: note: initializing argument 1 of ‘void not_working(std::shared_ptr<A>&)’ 18 | void not_working(std::shared_ptr<A>& ptr) { | ~~~~~~~~~~~~~~~~~~~~^~~ make: *** [<builtin>: main] Error 1
原因解析
核心问题在于C++的引用绑定规则:
- 当你将
std::shared_ptr<B>传递给期望std::shared_ptr<A>&的函数时,编译器会触发std::shared_ptr的转换构造函数,创建一个临时的std::shared_ptr<A>对象(因为B是A的子类,shared_ptr支持这种向上转型)。 - 这个临时对象属于右值,C++明确规定:非const的左值引用(
&)无法绑定到右值,但const左值引用(const &)可以绑定到右值,并且会延长临时对象的生命周期。
具体到代码:
- 调用
working(ptr)时,参数是const std::shared_ptr<A>&,临时生成的std::shared_ptr<A>可以合法绑定到这个const引用上,因此编译通过,且多态调用正常(ptr->foo()会调用B的foo)。 - 调用
not_working(ptr)时,参数是std::shared_ptr<A>&,临时的std::shared_ptr<A>是右值,无法绑定到非const左值引用,因此触发编译错误。
解决方法
如果确实需要在not_working中修改传入的shared_ptr(比如重置它),可以提前将std::shared_ptr<B>显式转换为std::shared_ptr<A>再传递:
std::shared_ptr<A> a_ptr = ptr; not_working(a_ptr);
如果不需要修改传入的shared_ptr,使用const std::shared_ptr<A>&是最优选择——它既支持多态场景的隐式转换,又避免了不必要的shared_ptr拷贝。
内容的提问来源于stack exchange,提问作者antibus
相关产品推荐
相关产品推荐

