C++运行时自省问题:父类对象赋值子类实例后调用方法未执行子类逻辑
Hey there, let's figure out why your child class's doSomething() isn't running, and how to fix it—including using C++ runtime introspection (RTTI) as you asked!
You're hitting two key C++ pitfalls here: object slicing and static binding. Let's break them down:
1. Object Slicing is Truncating Your Child Object
That line MyClass foo = MyChildClass(); is the first problem. When you assign a child class object to a parent class variable by value, C++ "slices off" all parts of the object that are unique to the child. The result? foo is a pure MyClass instance, not a MyChildClass—so it calls the parent's empty doSomething() every time.
2. Missing virtual Means Static Binding
Your parent class's doSomething() isn't marked virtual. By default, C++ uses static binding: it picks which function to call at compile time based on the variable's declared type, not the actual type of the object it holds. Even if you avoided slicing, without virtual, the compiler would still call MyClass::doSomething() because foo is declared as MyClass.
Also, a quick critical note: your MyChildClass uses private inheritance by default (since you didn't write public MyClass). Private inheritance doesn't let you treat the child as a parent type for polymorphism—always use public inheritance when you want subclassing for this purpose.
First, let's fix the core polymorphism issue, then add runtime introspection tools.
Step 1: Set Up Proper Polymorphism
Update your classes to use virtual functions and public inheritance:
class MyClass { public: virtual void doSomething() { // Mark as virtual for dynamic binding // Empty implementation }; virtual ~MyClass() = default; // Add virtual destructor to avoid memory leaks }; class MyChildClass : public MyClass { // Public inheritance for polymorphism public: void doSomething() override { // Use override to confirm we're rewriting a virtual method // Your actual business code here }; };
Now, use pointers or references (not value types) to avoid slicing:
// Using raw pointers (remember to delete!) MyClass* foo = new MyChildClass(); foo->doSomething(); // Now calls MyChildClass::doSomething() delete foo; // Virtual destructor ensures proper cleanup // Or safer: use smart pointers #include <memory> std::unique_ptr<MyClass> foo = std::make_unique<MyChildClass>(); foo->doSomething();
Step 2: Add Runtime Introspection (RTTI)
If you need to check the actual type of an object at runtime (introspection), C++ provides two tools: typeid and dynamic_cast.
Using typeid to Check Object Type
typeid lets you get the runtime type of an object. Include <typeinfo> to use it:
#include <typeinfo> #include <iostream> MyClass* foo = new MyChildClass(); if (typeid(*foo) == typeid(MyChildClass)) { std::cout << "foo is actually a MyChildClass instance!" << std::endl; // You can safely cast to the child type here if needed static_cast<MyChildClass*>(foo)->doSomething(); }
Using dynamic_cast for Safe Type Casting
dynamic_cast checks if a cast between polymorphic types is valid at runtime. It returns nullptr for pointers if the cast fails, or throws an exception for references:
MyClass* foo = new MyChildClass(); // Try to cast to MyChildClass* if (MyChildClass* childFoo = dynamic_cast<MyChildClass*>(foo)) { childFoo->doSomething(); // Call child-specific methods safely } else { // Cast failed—foo isn't a MyChildClass foo->doSomething(); }
- Always use
publicinheritance when working with polymorphism (private inheritance isn't meant for this use case). - Mark base class methods as
virtualto enable dynamic binding (so the correct method is called based on the actual object type at runtime). - Use pointers or references instead of value types to avoid object slicing.
- RTTI tools like
typeidanddynamic_castlet you introspect object types at runtime, which is useful if you need to perform type-specific operations beyond basic polymorphism.
内容的提问来源于stack exchange,提问作者Christian Daley

