向下传送带有附加功能的派生类的共享指针 - 这样安全吗?

jed*_*rds 13 c++ stl shared-ptr downcast

请考虑以下大纲:

class Base { /* ... */ };

class Derived : public Base
{
public:
    void AdditionalFunctionality(int i){ /* ... */ }
};

typedef std::shared_ptr<Base> pBase;
typedef std::shared_ptr<Derived> pDerived;

int main(void)
{
    std::vector<pBase> v;
    v.push_back(pBase(new Derived()));

    pDerived p1(  std::dynamic_pointer_cast<Derived>(v[0])  ); /* Copy */
    pDerived p2 = std::dynamic_pointer_cast<Derived>(v[0]);    /* Assignment */

    p1->AdditionalFunctionality(1);
    p2->AdditionalFunctionality(2);

    /* A */

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这里我用扩展功能(AdditionalFunctionality方法)的派生类扩展基类.

第一个问题,这样可以吗?我已经阅读了很多问题,说这不合适,你应该在基类中声明附加功能(通常建议在基类中使它们成为纯虚方法).但是,我不想这样做.我想扩展基类的功能,而不仅仅是以不同的方式实现它.有没有更好的解决方案来实现这一目标?

好的,所以在这段代码中我也使用一个STL容器来存储这些指针,这些指针允许我存储指向Base类型对象的指针以及Derived类型的对象而不切片对象.

第二个问题,这是有道理的,对吗?事实上,我通过使用指向基类对象的指针而不是基类对象本身来避免切片?

如果我"知道"某个指针指向Derived对象,那么我将使用它std::dynamic_pointer_cast来转换智能指针.

第三个问题,这个编译没有任何警告和工作,但它是否安全?有效?它是否会打破共享指针的引用计数方面,并且在我预期之前无法访问delete我的对象或delete它们?

最后,我可以使用复制构造函数或通过赋值执行此转换,如p1和p2所示.这样做是否有首选/正确的方法?

类似的问题:

  • 将shared_ptr <Base>向下转换为shared_ptr <Derived>?:这是非常接近的,但是这个类没有像我一样增加额外的功能,所以我不确定它是完全一样的.此外,它使用boost::shared_ptr我正在使用的地方std::shared_ptr(虽然我理解提升捐赠shared_ptr到std库,所以它们可能是相同的).

谢谢您的帮助.


编辑:

我问的一个原因是我意识到可以完成以下操作(错误):

    /* Intentional Error */
    v.push_back(pBase(new Base()));
    pDerived p3( std::dynamic_pointer_cast<Derived>(v[1]) );
    p3->AdditionalFunctionality(3); /* Note 1 */
Run Code Online (Sandbox Code Playgroud)

我尝试将指向Base对象的指针向下转换为Derived对象的指针,然后调用仅在Derived类中实现的方法.换句话说,指向的对象没有定义(或甚至不知道"该方法").

这不会被编译器捕获,但可能会导致段错误,具体取决于AdditionalFunctionality定义的方式.

Kir*_*sky 9

是否Base有虚拟析构函数?如果是,那么使用向下转换是安全的.在你的错误样本中pDerived应该是NULL结果,所以你需要检查dynamic_pointer_cast每次的结果.