C ++ dynamic_ptr_cast for shared_ptr from base to derived error

This is the puzzle I encountered this week. This is partly because I just returned to C ++ coding after Java coding for a while. Given the following code:

class Base { }; class A : Base { public: virtual void run() { cout << "This is A." << endl; } }; class B : Base { public: virtual void run() { cout << "This is B." << endl; } }; class C : A, B { public: void run() { cout << "This is C." << endl; } }; int main(int argc, char* argv[]) { shared_ptr<A> ptrToA = shared_ptr<C>(new C()); cout << "Pointer to A: " << ptrToA.get() << endl; cout << "Dynamic Cast A ptr to C: " << dynamic_pointer_cast<C>(ptrToA) << endl; ptrToA->run(); assert(dynamic_pointer_cast<C>(ptrToA)); cout << "Success!" << endl; } 

Why does he make the following conclusion?

 Pointer to A: 0x1f29c010 Dynamic Cast A ptr to C: 0 Running... This is C. tester-cpp: tester.cpp:89: int main(int, char **): Assertion `dynamic_pointer_cast<C>(ptrToA)' failed. 

Since "This is C" prints out, it is obvious that polymorphism works, but it fails when the dynamic casting of shared_ptr from the base class "A" to "C". This week I spent a lot of time on this subtle question! We hope that any answers will save future coders with a similar problem, spending so much time (the error was very subtle, especially after coding Java for a while).

Why? (I will give you a hint ... this code was compiled with the Intel C ++ 12.1.0 compiler on Linux. I tried it with another compiler, and my code is not compiled!)

+4
source share
1 answer

The fact that it cannot compile another compiler is a hint: it really should not compile. This is because C privately inherited from A and B , so C* should not be converted to A* . Therefore, shared_ptr<A> ptrToA = shared_ptr<C>(new C()); should not be compiled, since the conversation designer should only participate in overload resolution, when the pointer can be converted in accordance with the standard. So it looks like an error in the standard library used by Intel C ++.

Change Class C: A, B to Class C: public A, public B , and it should work. Testing on gcc 4.6, the code really fails to compile with private inheritance and works the same way as with public A inheritance.

Since your code contains diamond inheritance , you can also take a look at virtual inheritance .

+7
source

Source: https://habr.com/ru/post/1393235/


All Articles