C++多态场景疑问:派生类Getter为何返回基类指针及解决方法
问题解答
1. 为什么调用正确的重写函数却返回BaseType指针?
这里有两个核心原因:
- 协变返回类型的静态类型推导:C++允许重写虚函数时使用协变返回类型——派生类的重写函数可以返回基类返回类型的派生类指针/引用(这里
TypeA*是BaseType*的派生类型)。但当你通过Base*调用GetObject()时,编译器在编译阶段只能识别Base类中声明的返回类型BaseType*,因此auto* obj_ptr会被推导为BaseType*,这是变量的静态类型。 - typeid对非多态指针的行为:
typeid作用于指针本身时,只会返回该指针的静态类型,不会追踪它指向对象的动态类型。同时你的BaseType类没有任何虚函数,不属于多态类,即使使用typeid(*obj_ptr),也无法获取实际对象的动态类型(因为没有虚函数表支持RTTI运行时类型识别)。
你看到的"i'm comming from DerivedA/B"证明多态调用是生效的——实际执行的是派生类的重写函数,返回的指针确实指向TypeA/TypeB对象,但变量的静态类型是BaseType*,所以typeid输出的是静态类型的名称。
2. 如何修改代码获取TypeA/TypeB类型的指针?
方案1:使用dynamic_cast实现动态类型转换(需多态类支持)
首先要让BaseType成为多态类(添加至少一个虚函数,通常推荐虚析构函数,避免内存泄漏),然后就可以用dynamic_cast尝试将BaseType*转换为TypeA*或TypeB*:
#include <iostream> #include <vector> #include <typeinfo> using namespace std; class BaseType { public: // 添加虚析构函数,让BaseType成为多态类 virtual ~BaseType() = default; }; class TypeA : public BaseType {}; class TypeB : public BaseType {}; class Base { public: virtual BaseType* GetObject() = 0; virtual ~Base() = default; // 给Base加虚析构,避免内存泄漏 }; class DerivedA: public Base { public: TypeA* object = new TypeA(); TypeA* GetObject() override { cout << "i'm comming from DerivedA" << endl; return object; } ~DerivedA() override { delete object; } }; class DerivedB: public Base { public: TypeB* object = new TypeB(); TypeB* GetObject() override { cout << "i'm comming from DerivedB" << endl; return object; } ~DerivedB() override { delete object; } }; int main() { vector<Base*> vec = {new DerivedA(), new DerivedB()}; for (auto* item : vec){ BaseType* obj_ptr = item->GetObject(); // 尝试转换为TypeA* if (TypeA* a_ptr = dynamic_cast<TypeA*>(obj_ptr)) { cout << "I have an object of type " << typeid(a_ptr).name() << endl; cout << "Dynamic type of object: " << typeid(*a_ptr).name() << endl; } // 尝试转换为TypeB* else if (TypeB* b_ptr = dynamic_cast<TypeB*>(obj_ptr)) { cout << "I have an object of type " << typeid(b_ptr).name() << endl; cout << "Dynamic type of object: " << typeid(*b_ptr).name() << endl; } } // 清理内存 for (auto* item : vec) { delete item; } }
方案2:仅查看对象的动态类型(无需转换指针)
如果只是想确认指针指向对象的实际类型,只需让BaseType成为多态类,然后使用typeid(*obj_ptr)即可获取动态类型:
// 仅修改BaseType类,其他部分不变 class BaseType { public: virtual ~BaseType() = default; }; // main函数中修改输出行 cout << "I have an object of dynamic type " << typeid(*obj_ptr).name() << endl;
运行后会输出类似:
i'm comming from DerivedA I have an object of dynamic type 5TypeA i'm comming from DerivedB I have an object of dynamic type 5TypeB
内容的提问来源于stack exchange,提问作者Lupino
相关产品推荐
相关产品推荐

