C++中基类继承 enable_shared_from_this 之后派生类无法使用 shared_from_this() 的解决方法
2016-10-23 13:13
525 查看
在很多情况下,我们会在基类中继承 std::enable_shared_from_this 来使得在该类的方法中能够使用 shared_ptr 托管的 this 指针。例如:
但如果在子类中使用 shared_from_this() 函数,就会发生错误。例如:
分析其原因,是因为 Base 在继承enable_shared_from_this<T>时,向模板T传递的类型为Base,也就是 shared_from_this() 函数返回值类型被设定为了 std::shared_ptr<Base>。所以在 Derived 中调用 shared_from_this(),返回值就是std::shared_ptr<Base>了。由于我们无法将裸指针或是智能指针从基类隐性转换至派生类,所以会发生以上错误。
这时我们就需要显性的对返回值类型进行转换。
解决方法是使用std::dynamic_pointer_cast<Derived>(shared_from_this())将返回的指针转换为派生类类型的指针:
最后需要注意两点:
1. 使用std::dynamic_pointer_cast<T>()需要基类中存在虚函数,这是由于这个转换函数使用输入的类型和目标类型中是否存在相同签名的虚函数作为转换能否成功的标识。最简单也是正确的解决方法是将基类中的析构函数声明为虚函数。
2. 不能在构造函数中使用shared_form_this()。这是由于std::enable_share_from_this在实现时使用了一个对象的weak_ptr,而这个weak_ptr需要对象的shared_ptr进行初始化。由于此时对象尚未构造完成,所以会抛出std::bad_weak_ptr的异常。关于这点目前没有较为完美的方案,可以尝试写一个init()函数,在对象构造后手动调用。或是手动写一个std::shared_ptr<Derived>(this)使用,但这种解决方案可能造成循环引用。更多方案请查阅StackOverFlow。
class Base : public std::enable_shared_from_this<Base> { public: Base() { /* ... */ } ~Base() { } void method() { // ... // 传递该类shared_ptr托管的this指针 function1(shared_from_this()); } // ... private: // ... }; void function1(std::shared_ptr<Base> derived) { // ... }
但如果在子类中使用 shared_from_this() 函数,就会发生错误。例如:
class Derived : public Base { public: Derived() { /* ... */ } ~Deried() { } void method(std::shared_ptr<Derived> derived) { // ... // 错误:不存在用户定义的从“std::shared_ptr<Base>”到“std::shared_ptr<Derived>”的适当转换 function2(shared_from_this()); } private: // ... }; void function2(std::shared_ptr<Derived> derived) { // ... } int main() { std::shared_ptr<Derived> derived = std::make_shared<Derived>(); derived->method(); return 0; }
分析其原因,是因为 Base 在继承enable_shared_from_this<T>时,向模板T传递的类型为Base,也就是 shared_from_this() 函数返回值类型被设定为了 std::shared_ptr<Base>。所以在 Derived 中调用 shared_from_this(),返回值就是std::shared_ptr<Base>了。由于我们无法将裸指针或是智能指针从基类隐性转换至派生类,所以会发生以上错误。
这时我们就需要显性的对返回值类型进行转换。
解决方法是使用std::dynamic_pointer_cast<Derived>(shared_from_this())将返回的指针转换为派生类类型的指针:
class Derived : public Base { public: Derived() { /* ... */ } virtual ~Derived() { } void method(std::shared_ptr<Derived> derived) { // ... // shared_from_this()的返回值类型为std::shared_ptr<Base>,使用std::dynamic_pointer_cast<Derived>函数将其转为std::shared_ptr<Derived>类型 std::shared_ptr<Derived> pointer = std::dynamic_pointer_cast<Derived>(shared_from_this()); function2(pointer); } private: // ... };
最后需要注意两点:
1. 使用std::dynamic_pointer_cast<T>()需要基类中存在虚函数,这是由于这个转换函数使用输入的类型和目标类型中是否存在相同签名的虚函数作为转换能否成功的标识。最简单也是正确的解决方法是将基类中的析构函数声明为虚函数。
2. 不能在构造函数中使用shared_form_this()。这是由于std::enable_share_from_this在实现时使用了一个对象的weak_ptr,而这个weak_ptr需要对象的shared_ptr进行初始化。由于此时对象尚未构造完成,所以会抛出std::bad_weak_ptr的异常。关于这点目前没有较为完美的方案,可以尝试写一个init()函数,在对象构造后手动调用。或是手动写一个std::shared_ptr<Derived>(this)使用,但这种解决方案可能造成循环引用。更多方案请查阅StackOverFlow。
相关文章推荐
- enable_from_this方法的使用与陷阱
- weak_ptr,enable_shared_from_this 的使用举例
- Image.FromFile方法会锁住文件的解决方法(文件正由另一进程使用,因此该进程无法访问该文件)
- 关于集成环信3.0之后,应用无法在安卓5.0以下使用的解决方法
- 使用enable_shared_from_this
- 使用enable_shared_from_this
- C++学习 std::tr1::shared_ptr、std::tr1::weak_ptr及std::tr1::enable_shared_from_this
- C++中使用基类指针调用派生类中定义的方法
- 使用enable_shared_from_this
- 使用JavaScript脚本无法直接改变Asp.net中Checkbox控件的Enable属性的解决方法
- enable_shared_from_this模板类使用完全解析
- boost::shared_ptr递归调用解决办法--boost::enable_shared_from_this
- stm32之 GPIO_Remap_SWJ_Disable之后无法使用swd下载 程序解决方法
- Image.FromFile方法会锁住文件的解决方法(文件正由另一进程使用,因此该进程无法访问该文件)
- 使用enable_shared_from_this示例
- 类的 继承 使用关键字 extends 单向 重载基类 派生类访问基类的方法 基类名::基类方法或属性
- 使用JavaScript脚本无法直接改变Asp.net中Checkbox控件的Enable属性的解决方法
- 使用JavaScript脚本无法直接改变Asp.net中Checkbox控件的Enable属性的解决方法
- [ios]xcode更新之后插件无法使用的解决方法
- 使用JavaScript脚本无法直接改变Asp.net中Checkbox控件的Enable属性的解决方法