Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I dynamic upcast and downcast with smart pointers?

I have some code with a generic interface in which I need to cast up and down. I'm trying to convert to smart pointers now, but am running into some errors. The code below reproduces the problem. I'm using C++14, so I think this stuff is supposed to work automagically now?

#include <memory>
#include <iostream>
int main()
{
    std::shared_ptr<int> a(new int);
    *a = 5;
    std::shared_ptr<void> b = std::dynamic_pointer_cast<void>(a);
    std::shared_ptr<int> c = std::dynamic_pointer_cast<int>(b);
    std::cout << *c; //should be 5
    return 0;
}

However, when I try to compile this, I get:

Error   C2680   '_Elem1 *': invalid target type for dynamic_cast    
Error   C2681   'int *': invalid expression type for dynamic_cast   

Guessing I did something dumb in the syntax?

like image 793
Carbon Avatar asked Apr 28 '17 14:04

Carbon


People also ask

What is dynamic pointer cast?

A pointer (or reference) to a class can actually point (refer) to any class derived from that class. Occasionally, it may be desirable to obtain a pointer to the fully derived class, or to some other subobject of the complete object. The dynamic cast provides this facility.

What is the use of Upcasting and downcasting in C++?

Upcasting can cause object slicing when a derived class object is passed by value as a base class object, as in foo(Base derived_obj). The opposite process, converting a base-class pointer (reference) to a derived-class pointer (reference) is called downcasting. Downcasting is not allowed without an explicit type cast.

What is the difference between static casting and dynamic casting?

Static casting is done by the compiler: it treats the result as the target type, no matter what. You do this when you're absolutely sure about the argument being of the target type. Dynamic casting is done at runtime, and thus requires runtime type information.

Is used for downcasting base class pointers?

A dynamic cast expression is used to cast a base class pointer to a derived class pointer. This is referred to as downcasting.


2 Answers

The rules are the same as for dumb pointers, except you have to use std::static_pointer_cast and std::dynamic_pointer_cast instead of static_cast and dynamic_cast. C++17 will introduce the counterpart for reinterpret_cast, but that is not needed for up- or down casts, nor for conversions from or to void.

How do I dynamic upcast ... with smart pointers?

Conversion up in type hierarchy is implicit, so there is no need for a cast:

struct A{
    virtual ~A(){}
};
struct B:A{};

auto b = std::make_shared<B>();
std::shared_ptr<A> a = b;

How do I dynamic ... downcast with smart pointers?

Using std::dynamic_pointer_cast if you're unsure whether the source points to the correct type. This is only possible if the inheritance is polymorphic (i.e. the base has at least one virtual function):

b = std::dynamic_pointer_cast<B>(a);

Or std::static_pointer_cast if you know that the type is correct:

b = std::static_pointer_cast<B>(a);

std::shared_ptr<void> b = std::dynamic_pointer_cast<void>(a);
std::shared_ptr<int> c = std::dynamic_pointer_cast<int>(b);

void and int do not have an inheritance relationship so they can not be up- or down casted.

However, all pointers are implicitly convertible to a void pointer, so an implicit conversion is possible:

 std::shared_ptr<void> b = a;

And, void pointers can be static casted to the original type, so you can use std::static_pointer_cast:

std::shared_ptr<int> c = std::static_pointer_cast<int>(b);
like image 107
eerorika Avatar answered Nov 01 '22 17:11

eerorika


Since C++17, you have std::reinterpret_pointer_cast

like image 30
Jarod42 Avatar answered Nov 01 '22 19:11

Jarod42