无法使用赋值语法通过派生类shared_ptr构造对象,如何解决?
问题分析与解决办法
问题原因
A a1(data)属于直接初始化,C++允许这个过程中进行一次隐式转换:std::shared_ptr<derived>可以隐式转换为std::shared_ptr<base>,随后调用A的构造函数,因此编译通过。
而A a2 = data属于拷贝初始化,这个过程需要两次连续的隐式转换:先将std::shared_ptr<derived>转为std::shared_ptr<base>,再将后者转为A实例。但C++标准规定,拷贝初始化仅允许一次用户定义的隐式转换,因此这行代码编译失败。
解决办法
办法1:显式转换data类型
通过显式将data转为std::shared_ptr<base>,让拷贝初始化仅需一次转换:
#include <memory> struct base { virtual ~base() {} }; struct derived : public base {}; struct A { A(std::shared_ptr<base> x) {} }; int main() { std::shared_ptr<derived> data = std::make_shared<derived>(); A a1(data); // ok A a2 = static_cast<std::shared_ptr<base>>(data); // 显式转换后可正常编译 return 0; }
办法2:为A添加模板构造函数
新增模板构造函数,直接接受任意继承自base的std::shared_ptr<T>,避免两次隐式转换:
#include <memory> #include <type_traits> struct base { virtual ~base() {} }; struct derived : public base {}; struct A { A(std::shared_ptr<base> x) {} // 模板构造函数,仅匹配继承自base的类型 template<typename T, typename = std::enable_if_t<std::is_base_of_v<base, T>>> A(std::shared_ptr<T> x) : A(std::static_pointer_cast<base>(x)) {} }; int main() { std::shared_ptr<derived> data = std::make_shared<derived>(); A a1(data); // ok A a2 = data; // 现在可正常编译 return 0; }
办法3:直接构造临时A实例
拷贝初始化可以直接接受临时A对象,此时仅需一次隐式转换(data转std::shared_ptr<base>构造临时A):
#include <memory> struct base { virtual ~base() {} }; struct derived : public base {}; struct A { A(std::shared_ptr<base> x) {} }; int main() { std::shared_ptr<derived> data = std::make_shared<derived>(); A a1(data); // ok A a2 = A(data); // 构造临时A,可正常编译 return 0; }
内容的提问来源于stack exchange,提问作者mxmxlwlw
相关产品推荐
相关产品推荐

