zhangzhimin
zhangzhimin

Reputation: 141

How can I cast a base smart pointer into the derived one in C++?

Code :

class Base {
    ...
};

class Derived : public Base {
    void OnlyOwnedByDerived{
        ...
    }
};

The question is : 1. If I used a smart pointer of the Base class to reference the Derived one, the reason why I do so is that I want to get the benefit of dynamic binding which only fits virtual functions. But if I want to to use the function that is only owned by the derived class, what should I do ? static_cast between the smart pointer of different class gives me an error...

  1. The most direct way I can come up with is use raw pointer rather than smart one...

Upvotes: 1

Views: 3425

Answers (3)

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145279

For the smart pointer itself it depends on the smart pointer. A smart pointer to Derived is not a class derived from that kind of smart pointer to Base. But you can cast the raw pointer. For that you have static_cast if you know the pointee is of derived type, and dynamic_cast for when you don't know (or just desire the checking) and the base class is polymorphic.

Note: Ownership assumptions can be broken if the raw pointer is downcasted and then used to construct a new smart pointer. For this case the original smart pointer's ownership should be released first. Usually that's a member function called release.

For example:

#include <iostream>
#include <memory>

struct Base
{
    int x;
};

struct Derived
    : Base
{
    void foo() const { std::cout << x << "\n"; }
    Derived( int const value ): Base{ value } {}
};

auto main()
    -> int
{
    using std::unique_ptr;
    unique_ptr<Base> p_base{ new Derived{ 42 } };

    #ifdef CHECK
        unique_ptr<Derived> p_directly_converted{ p_base };     // !Nyet
    #endif

    unique_ptr<Derived> p_derived{
        static_cast<Derived*>( p_base.release() )
        };
    p_derived->foo();
}

std::unique_ptr doesn't have an associated function that performs this downcast, so it must be done manually via either static_cast or dynamic_cast (for a polymorphic base), plus release.

However, std::shared_ptr has associated functions static_pointer_cast, dynamic_pointer_cast and const_pointer_cast, and other smart pointers may have ditto functions – but this depends very much on the smart pointer.

Upvotes: 0

WhiZTiM
WhiZTiM

Reputation: 21576

In C++11, there is the dynamic_pointer_cast

Which you can use:

void func(std::shared_ptr<Base> b){
    b->VirtualBaseFunction();
    if(auto d = dynamic_pointer_cast<Derived>(b)){
         d->DerivedSpecificFunction():
         ....more code
    }
}

Upvotes: 6

Yuushi
Yuushi

Reputation: 26040

By using std::dynamic_pointer_cast. This will return an empty shared_ptr if the cast is not successful.

You could potentially also use dynamic_cast directly on the pointer managed by the smart pointer, if you don't want the ownership to be shared between the returned derived pointer:

smart_ptr_type<Base> x = ...;
auto* derived = dynamic_cast<Derived*>(x.get());

Upvotes: 3

Related Questions