Reflection and Introspection in C++: How to Make Code See Itself

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

What are Reflection and Introspection in C++ and Why Do You Need Them?

\n\n

Imagine you are writing a complex game engine or a data processing framework. At some point, you need to understand: "What kind of object is this? What methods does it have? Does it have a name field?"

\n\n

In languages like Python or Java, this is done in one line — they have full reflection (the ability of a program to examine and modify its own structure at runtime). In C++, however, things are more complicated. C++ is a strongly statically typed language, and there is almost no reflection "out of the box." But there is introspection — a limited ability to obtain information about types at runtime.

\n\n

In this article, we will cover:

\n
    \n
  • How reflection differs from introspection;
  • \n
  • How RTTI (Run-Time Type Information) works;
  • \n
  • How to use typeid and dynamic_cast;
  • \n
  • How to emulate reflection using templates and macros;
  • \n
  • Modern alternatives (C++20/23) and libraries.
  • \n
\n\n

Ready to look into the "looking glass" of C++? Let's go!

\n\n

Introspection vs Reflection: What's the Difference?

\n\n

Before writing code, let's dot the i's.

\n\n
    \n
  • Introspection is the ability of a program to "look at itself" and obtain information about types, but not modify the program's structure. For example: "Find out the class name of an object." This exists in C++ via RTTI.
  • \n
  • Reflection is introspection + the ability to dynamically create objects, call methods, and modify fields. This is not in the C++ standard (yet).
  • \n
\n\n

In C++, we use the term "reflection" more often as a goal, and "introspection" as an available tool. But don't be afraid: even with limited tools, you can do cool things.

\n\n

RTTI (Run-Time Type Information) — The Foundation of Introspection in C++

\n\n

RTTI is a mechanism that allows you to determine the type of an object at runtime. It is enabled by default (although in some embedded systems it is disabled with the -fno-rtti flag).

\n\n

The main players of RTTI:

\n
    \n
  • typeid — an operator that returns std::type_info;
  • \n
  • dynamic_cast — safe casting of polymorphic types.
  • \n
\n\n

Example 1: Using typeid

\n\n
#include <iostream>\n#include <typeinfo>\n\nclass Base { virtual void foo() {} };\nclass Derived : public Base {};\n\nint main() {\n    Base* b = new Derived();\n    std::cout << "Object type: " << typeid(*b).name() << std::endl;\n    delete b;\n    return 0;\n}
\n\n

Output (depends on compiler): class Derived or 7Derived (mangled name).

\n\n

Note: typeid only works with polymorphic classes (having at least one virtual method). If you remove virtual, you will get the type of the pointer, not the actual object.

\n\n

Example 2: dynamic_cast — Safe Casting

\n\n
#include <iostream>\n\nclass Animal { public: virtual ~Animal() = default; };\nclass Dog : public Animal { public: void bark() { std::cout << "Woof!\\n"; } };\nclass Cat : public Animal { public: void meow() { std::cout << "Meow!\\n"; } };\n\nvoid makeSound(Animal* a) {\n    if (Dog* dog = dynamic_cast<Dog*>(a)) {\n        dog->bark();\n    } else if (Cat* cat = dynamic_cast<Cat*>(a)) {\n        cat->meow();\n    } else {\n        std::cout << "Unknown animal\\n";\n    }\n}\n\nint main() {\n    Animal* pets[] = { new Dog(), new Cat(), new Animal() };\n    for (auto p : pets) makeSound(p);\n    // Don't forget to delete!\n    for (auto p : pets) delete p;\n    return 0;\n}
\n\n

This is a classic example of introspection: we don't know exactly which object came in, but we can

Blogs

Book Recommendations