Thread: Dynamic cast with std::shared_ptr

  1. #1
    Registered User
    Join Date
    Mar 2016
    Posts
    203

    Dynamic cast with std::shared_ptr

    I took the RTTI/dynamic_cast example from C++ Primer Plus (5th ed), Stephen Prata that uses C-style pointers and tried to get it working with std::shared_ptr. In the program below the counterpart raw pointer code is beneath each corresponding use of the smart pointer:
    Code:
    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    #include <memory>
    
    
    class Grand
    {
        private:
            int hold;
        public:
            Grand(int h = 0) : hold(h) {}
            virtual void Speak() const { std::cout << "I am a grand class!\n";}
            virtual int Value() const { return hold; }
    };
    class Superb : public Grand
    {
        public:
            Superb(int h = 0) : Grand(h) {}
            void Speak() const {std::cout << "I am a superb class!!\n"; }
            virtual void Say() const
            {std::cout << "I hold the superb value of " << Value() << "! \n";}
    };
    class Magnificent : public Superb
    {
        private:
            char ch;
        public:
            Magnificent(int h = 0, char c = 'A') : Superb(h), ch(c) {}
            void Speak() const {std::cout << "I am a magnificent class!!!\n";}
            void Say() const {std::cout << "I hold the character " << ch <<
            " and the integer "  << Value() << "!\n"; }
            Grand * GetOne();
    };
    std::shared_ptr<Grand> GetOne();
    //Grand * GetOne();
    int main()
    {
        std::srand(std::time(0));
        //Grand * pg;
        std::shared_ptr<Grand> pg;
        //Superb * ps;
        std::shared_ptr<Superb> ps;
        for (int i = 0; i < 5; i++)
        {
            pg = GetOne();
            pg->Speak();
            if( ps = dynamic_cast<std::shared_ptr<Superb>>(pg))
            //if(ps = dynamic_cast<Superb*>(pg))
            ps->Say();
        }
    }
    std::shared_ptr<Grand> GetOne()    // generate one of three kinds of objects randomly
    {
        std::shared_ptr<Grand> p;
        switch( std::rand() % 3)
        {
            // case 0: p = new Grand(std::rand() % 100);
            case 0: p = std::make_shared<Grand>(std::rand() % 100);
            break;
            //case 1: p = new Superb(std::rand() % 100);
            case 1: p = std::make_shared<Superb> (std::rand() % 100);
            break;
            //case 2: p = new Magnificent(std::rand() % 100, 'A' + std::rand()%26);
            case 2: p = std::make_shared<Magnificent>(std::rand() % 100, 'A' + std::rand()%26);
            break;
        }
        return p;
    }
    //ERROR MESSAGE:
    |48|error: cannot dynamic_cast 'pg' (of type 'class std::shared_ptr<Grand>') to type 'class std::shared_ptr<Superb>' (target is not pointer or reference)|
    Though the expression is within an if-statement it seems the compiler does not want to proceed in the case of std::shared_ptr though it compiles with raw pointers and the dynamic_cast is valid for resultant objects of type Superb and Magnificent.
    Why does this happen and is there a way to make it work with std::shared_ptr?
    Many thanks
    PS: I am not using std::unique_ptr yet as it's copy assignment is deleted and did not want to get into move semantics before trying to make std::shared_ptr work

  2. #2
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,616
    Code:
    if ( ps = std::dynamic_pointer_cast<Superb>(pg) )
       ps->Say();
    It basically does this, but also the use count is correct by using the function.
    Code:
    dynamic_cast<Superb*>(pg.get());
    In case it's wasn't clear, don't avoid using the function.
    Last edited by whiteflags; 01-21-2017 at 09:32 PM.

  3. #3
    Registered User
    Join Date
    Mar 2016
    Posts
    203
    whiteflags: what a beautiful, elegant solution! I did tinker with std::dynamic_pointer_cast before OP but clearly I was barking up the wrong tree! Your second block of code also gave me the idea re std::unique_ptr in this case:
    Code:
    	std::unique_ptr<Grand> pg = GetOne();//move assignment r-value
            pg->Speak();
    
    
            std::unique_ptr<Superb> ps(dynamic_cast<Superb*>(pg.get()));
            if(ps)
            {
              pg.release();
              ps->Say();
            }
    Many thanks.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. ~shared_ptr() block until shared_ptr::unique is true
    By CodeMonkey in forum C++ Programming
    Replies: 10
    Last Post: 12-17-2014, 09:28 PM
  2. When to use shared_ptr?
    By hpesoj in forum C++ Programming
    Replies: 15
    Last Post: 07-22-2008, 04:33 AM
  3. Is shared_ptr dangerous?
    By Elysia in forum C++ Programming
    Replies: 19
    Last Post: 04-07-2008, 02:02 AM
  4. boost::shared_ptr and dynamic binding
    By Mario F. in forum C++ Programming
    Replies: 2
    Last Post: 07-24-2006, 03:50 PM
  5. Dynamic Cast Errors
    By peking1983 in forum C++ Programming
    Replies: 3
    Last Post: 02-11-2003, 09:26 PM

Tags for this Thread