1

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...
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
zhangzhimin
  • 141
  • 1
  • 10

3 Answers3

6

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
    }
}
WhiZTiM
  • 21,207
  • 4
  • 43
  • 68
3

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());
Yuushi
  • 25,132
  • 7
  • 63
  • 81
  • I don't see a constraint to `shared_ptr` only; I don't even see it mentioned. So as the question stands, this is at best a comment. In the case of `shared_ptr`... – Cheers and hth. - Alf Aug 03 '16 at 03:33
  • Because there's not enough information, I have to make -some- assumption. Since all smart pointer types in the standard library can be converted to shared_ptr, it can be thought of as the "lowest common denominator". If they're using boost, then this should give them enough information to locate `boost::dynamic_pointer_cast`. You're welcome to ask for more specific information and answer the question yourself. – Yuushi Aug 03 '16 at 03:57
0

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.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331