Search code examples
c++11gcccastingpolymorphismshared-ptr

How do I implement polymorphism with std::shared_ptr?


I have seen some of the other questions on this topic, but have still not found the answer - I guess I'm missing something:

I defined two simple test classes:

class TestBase
{

  public:

    TestBase ( ) { };
    ~ TestBase ( ) { };

  protected:

    inline virtual int getInt ( )
    {
        return 0;
    }

};

class TestDerived : public TestBase
{

  protected:

    inline int getInt ( ) override
    {
        return 1;
    }

};

I declared typedefs to simplify their usage with std::shared_ptr:

typedef std::shared_ptr<TestBase> spBase;
typedef std::shared_ptr<TestDerived> spDerived;

Problem: I cannot compile code to use these shared_ptr declarations polymorphically, even though base in all these cases is actually an instance of spDerived:

spBase base;
spDerived derived = static_cast < spDerived > ( base );

error: no matching function for call to ‘std::shared_ptr::shared_ptr(spBase&)

spDerived derived = dynamic_cast < spDerived > ( base );

error: cannot dynamic_cast ‘base’ (of type ‘spBase {aka class std::shared_ptr}’) to type ‘spDerived {aka class std::shared_ptr}’ (target is not pointer or reference)

spDerived derived = static_pointer_cast < spDerived > ( base );

error: conversion from ‘std::shared_ptr >’ to non-scalar type ‘spDerived {aka std::shared_ptr}’ requested

spDerived derived = dynamic_pointer_cast < spDerived > ( base );

error: conversion from ‘std::shared_ptr >’ to non-scalar type ‘spDerived {aka std::shared_ptr}’ requested

I'm using C++11 on an Ubuntu 14.04 box with the default GCC tool chain. Compiler is gcc-4.9. What am I doing wrong? Can't a shared_pointer be used polymorphically?


Solution

  • A type passed in to std::static_pointer_cast and std::dynamic_pointer_cast as the first type template argument is the type of the converted pointer's type itself, not of the smart pointer type:

    static_pointer_cast<T>(arg);
                    .~~~^  
                    v 
    template <class T, class U> 
               .~~~~^  
               v 
    shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r);
    
    
    dynamic_pointer_cast<T>(arg);
                    .~~~~^  
                    v 
    template <class T, class U> 
               .~~~~^  
               v 
    shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& r);
    

    With that said, you could call it like below:

    spBase base = std::make_shared<TestDerived>();
    spDerived derived = std::dynamic_pointer_cast<spDerived::element_type>(base);
    // or:
    spDerived derived2 = std::dynamic_pointer_cast<TestDerived>(base);