如何在C++中实现运行时判断实例是否属于或继承自指定类?
在C++中实现类型/子类检查功能
可以实现,但C++没有C#那样直接的Type类型,需要依赖运行时类型信息(RTTI),且所有涉及的类必须是多态类型(包含至少一个虚函数,比如虚析构函数)。以下是两种可行的实现方案:
方案一:用封装类型检查逻辑的对象存储(最直观)
这种方式直接把类型的检查逻辑封装到对象中,存入向量后遍历检查即可:
#include <vector> #include <memory> #include <typeinfo> // 所有宠物类的基类,必须包含虚函数(这里用虚析构函数) class Pet { public: virtual ~Pet() = default; }; // 具体宠物类 class Dog : public Pet {}; class Labrador : public Dog {}; class Cat : public Pet {}; class Hamster : public Pet {}; // 抽象类型检查器 class TypeChecker { public: virtual bool matches(Pet* instance) const = 0; virtual ~TypeChecker() = default; }; // 针对具体类型的检查器模板 template <typename T> class ConcreteTypeChecker : public TypeChecker { public: bool matches(Pet* instance) const override { // dynamic_cast成功则说明instance是T或其子类 return dynamic_cast<T*>(instance) != nullptr; } }; int main() { // 构建合法类型的检查器向量 std::vector<std::unique_ptr<TypeChecker>> validCheckers; validCheckers.push_back(std::make_unique<ConcreteTypeChecker<Dog>>()); validCheckers.push_back(std::make_unique<ConcreteTypeChecker<Cat>>()); validCheckers.push_back(std::make_unique<ConcreteTypeChecker<Hamster>>()); // 测试实例 Pet* somePet = new Labrador(); bool isAllowed = false; // 遍历检查 for (const auto& checker : validCheckers) { if (checker->matches(somePet)) { isAllowed = true; break; } } // 输出结果:true(Labrador继承自Dog) printf(isAllowed ? "true\n" : "false\n"); delete somePet; return 0; }
方案二:用std::type_index存储类型信息
如果希望向量中存储的是"类型标识"而非检查函数,可以结合std::type_index和预注册的检查函数映射:
#include <vector> #include <unordered_map> #include <typeindex> #include <typeinfo> #include <functional> class Pet { public: virtual ~Pet() = default; }; class Dog : public Pet {}; class Labrador : public Dog {}; class Cat : public Pet {}; class Hamster : public Pet {}; int main() { // 预注册类型到检查函数的映射 std::unordered_map<std::type_index, std::function<bool(Pet*)>> typeCheckerMap; typeCheckerMap[std::type_index(typeid(Dog))] = [](Pet* p) { return dynamic_cast<Dog*>(p) != nullptr; }; typeCheckerMap[std::type_index(typeid(Cat))] = [](Pet* p) { return dynamic_cast<Cat*>(p) != nullptr; }; typeCheckerMap[std::type_index(typeid(Hamster))] = [](Pet* p) { return dynamic_cast<Hamster*>(p) != nullptr; }; // 构建合法类型的type_index向量 std::vector<std::type_index> validTypes; validTypes.push_back(std::type_index(typeid(Dog))); validTypes.push_back(std::type_index(typeid(Cat))); validTypes.push_back(std::type_index(typeid(Hamster))); // 测试实例 Pet* somePet = new Labrador(); bool isAllowed = false; // 遍历检查 for (const auto& typeIdx : validTypes) { auto it = typeCheckerMap.find(typeIdx); if (it != typeCheckerMap.end() && it->second(somePet)) { isAllowed = true; break; } } printf(isAllowed ? "true\n" : "false\n"); delete somePet; return 0; }
关键注意事项
- 必须启用RTTI:大多数编译器默认启用RTTI,但如果手动关闭了(比如GCC的
-fno-rtti选项),上述代码会失效。 - 多态类型要求:所有要检查的类必须继承自一个包含虚函数的基类,否则
dynamic_cast和typeid无法正确识别子类类型。 - 避免裸指针:示例中用了裸指针,实际项目建议用
std::unique_ptr或std::shared_ptr管理内存。
内容的提问来源于stack exchange,提问作者Ryan Pergent
相关产品推荐
相关产品推荐

