Skip to content

Advanced Gotchas

The typeid That Saw Only the Base

a base reference reveals less than the object holds

struct PlainBase {};
struct PlainDerived : PlainBase {};

struct PolymorphicBase {
  virtual ~PolymorphicBase() = default;
};
struct PolymorphicDerived : PolymorphicBase {};

int main() {
  PlainDerived plain;
  PlainBase& plain_view = plain;
  PolymorphicDerived dynamic;
  PolymorphicBase& dynamic_view = dynamic;

  std::cout << (typeid(plain_view) == typeid(PlainDerived)) << '\n';
  std::cout << (typeid(dynamic_view) == typeid(PolymorphicDerived)) << '\n';
}

Run it. Which base reference exposes its derived object?

Answer
0
1

Only the polymorphic base reference reports the dynamic type.

Why

typeid(expression) uses an expression's dynamic type only when its static class type is polymorphic. PlainBase has no virtual function, so typeid(plain_view) is determined from its static type; the virtual destructor makes PolymorphicBase polymorphic and enables the second lookup. A virtual base from virtual inheritance is a different feature and does not meet this requirement by itself. GCC emits no warning under -Wall -Wextra.

The fix

Give a base a virtual function when callers need runtime type identification:

struct Base { virtual ~Base() = default; };

Takeaway: typeid needs a polymorphic base (a virtual function), not virtual inheritance.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo

Open in Compiler Explorer ↗ Quiz this entry