0

Consider the following code:

#include <typeinfo>
#include<iostream>

class Parent
{
public:
   virtual void foo() const{};
};

class Child_A: public virtual Parent
{
};

void downcast( const Child_A& aa)
{
}

void upcast( const Parent& pp )
{
  std::cout<< typeid( pp ).name() << std::endl;
  downcast(pp); // line 21: This is the problematic line!
}


int main()
{
  Child_A aa;
  upcast(aa);
  return 0;
}

I get a compiling error:

initialization.cpp:21:14: error: invalid initialization of reference of type 'const Child_A&' from expression of type 'const Parent'

downcast(pp);

But if I compile the code without line 27, typeid( pp ).name() returns 7Child_A.

So why do I get this error? How can I fix it? and What is really the type of pp?

Eliad
  • 894
  • 6
  • 20
  • `typeid` is a runtime operator. Given just `upcast`, the compiler has no clue that `pp` is actually a `Child_A`. – chris Apr 17 '15 at 14:11
  • 2
    `pp` is a reference to `Parent`. You can't pass a reference to `Parent` to a function that expects a reference to `Child_A`. (And there's no casting in this code, only implicit conversion.) – molbdnilo Apr 17 '15 at 14:11
  • This question is overly complicated and could be pared down to a much smaller, representative example. – Kerrek SB Apr 17 '15 at 14:14

2 Answers2

3

Downcast cannot be done implicitly. To correct it, you can make the cast explicit through either static_cast or dynamic_cast. However, since Parent is a virtual base of Child_A. Only dynamic_cast applies here. So, to make your code correct, you could change downcast(pp); to downcast(dynamic_cast<const Child_A&>(pp));. Within void upcast( const Parent& pp ), the static type of pp is Parent but its dynamic type (real type) is Child_A. typeid queries dynamic type, and that is why 7Child_A gets printed.

Lingxi
  • 14,579
  • 2
  • 37
  • 93
3

You have an implicit derived-to-base conversion on the upcast(aa) line. pp refers to the base class subobject contained in aa. There is no implicit base-to-derived conversion. static_cast can be used to perform a downcast, but since Parent is a virtual base you'll have to use dynamic_cast instead:

if (Child_A* c = dynamic_cast<Child_A const*>(&pp)) {
    downcast(*c);
}

The line typeid(pp).name() returns a child class output string because when applied to an object of polymorphic type (Parent has a virtual method so it is polymorphic), the result is the most derived class:

When typeid is applied to a glvalue expression whose type is a polymorphic class type (10.3), the result refers to a std::type_info object representing the type of the most derived object (1.8) (that is, the dynamic type) to which the glvalue refers.

Note that pp's actual static type is Parent const&. typeid isn't a very reliable way to get the type of an object.

David G
  • 94,763
  • 41
  • 167
  • 253