5
votes

We have the general form of dynamic_cast:

dynamic_cast < new-type > ( expression )

I am specifically confused about the bold part of this rule (5a):

5: If expression is a pointer or reference to a polymorphic type Base, and new-type is a pointer or reference to the type Derived a run-time check is performed:

a) The most derived object pointed/identified by expression is examined. If, in that object, expression points/refers to a public base of Derived, and if only one object of Derived type is derived from the subobject pointed/identified by expression, then the result of the cast points/refers to that Derived object. (This is known as a "downcast".)

Can you please give an example where this part would not be satisfied?

The above extract comes from cppreference: cppreferenc

1
You can construct examples using multiple inheritance, in which some bases AND classes derived from common bases are inherited more than once by some concrete class. In that circumstance, the downcast from Base to Derived is ambiguous.Peter
@YoungBajwa, good question, I think you should add to it that the extract is coming from cppreference and add the link as wellAlessandro Teruzzi
@AlessandroTeruzzi edited and added note & link, thanksYoungOne

1 Answers

5
votes

Fleshing out the multiple inheritance example @Peter summarized:

     Base1
     /   \  <-- Virtual inheritance here
  Base2  Base2
    |     | <-- Nonvirtual inheritance here and below
  Left   Right
    \     /
    Derived

Base1* p_base1 = new Derived();
Base2* p_base2 = dynamic_cast<Base2*>(p_base1); // Which Base2?

There are two different Base2 objects within a Derived object, so which one should p_base2 point to?

Code example:

#include <iostream>

struct Base1 { virtual ~Base1() = default; };
struct Base2 : virtual Base1 { };
struct Left : Base2 { };
struct Right : Base2 { };
struct Derived : Left, Right {
    Derived() : Base1() {}
};

int main()
{
    Base1* p_base1 = new Derived();
    Base2* p_base2 = dynamic_cast<Base2*>(p_base1);
    std::cout << std::boolalpha;
    std::cout << "p_base1 == nullptr: " << (p_base1 == nullptr) << '\n';
    std::cout << "p_base2 == nullptr: " << (p_base2 == nullptr);
    delete p_base1;
}

Trying to be a little careful here: Base1 is inherited virtually so that there's only a single Base1 subobject and we can actually initialize p_base1. However, Derived inherits nonvirtually from Left and Right, meaning that it has two instances of Base2. Therefore, the downcast fails.

Output:

p_base1 == nullptr: false
p_base2 == nullptr: true