Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic cast specification (rule) clarification

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

like image 940
YoungOne Avatar asked Apr 08 '21 14:04

YoungOne


1 Answers

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
like image 154
Nathan Pierson Avatar answered Oct 30 '22 21:10

Nathan Pierson