首页 > 解决方案 > 使用 RTTI 从实现接口 c++ 的对象中获取类名

问题描述

我在 Animal 命名空间中有一个类 AnimalInterface:

namespace Animal
{
    class AnimalInterface
    {
    public:
        AnimalInterface() = default;
        virtual ~AnimalInterface() = default;

        virtual std::string makeSound() = 0;
    };
}

假设我有 2 个从这个接口实现的类

class Dog : public AnimalInterface
{
public:
    Dog() = default;
    ~Dog() = default;

    std::string makeSound()
    {
        return "Bark";
    }
};

class Cat : public AnimalInterface
{
public:
    Cat() = default;
    ~Cat() = default;

    std::string makeSound()
    {
        return "Meow";
    }
};

现在我有一个类,我从中调用这些函数。我希望能够使用运行时类型信息从对象中获取动物的类名。

void AnimalSounds
{
    list<unique_ptr<AnimalInterface>> animals;
    animals.push_back(make_unique<Dog>());
    animals.push_back(make_unique<Cat>());

    for (const auto& animal : animals)
    {

        cout << typeid(animal).name() << " makes sound: " << animal->makeSound() << endl;
    }
}

我希望输出是

Dog makes sound: Bark
Cat makes sound: Meow

相反,我得到以下

class std::unique_ptr<class Animal::AnimalInterface,struct std::default_delete<class Animal::AnimalInterface> > makes sound: Bark
class std::unique_ptr<class Animal::AnimalInterface,struct std::default_delete<class Animal::AnimalInterface> > makes sound: Meow

我该如何解决?谢谢!

标签: c++reflectionunique-ptr

解决方案


您需要取消引用指针。这样您就可以从它指向的对象而不是指针本身获取 RTTI 信息:

const auto& animal_ref = *animal;
cout << typeid(animal_ref).name() << " makes sound: " << animal->makeSound() << endl;
3Dog makes sound: Bark
3Cat makes sound: Meow

请注意,您仍然必须处理注释中描述的实现定义的名称。您可以为此使用库的 demangle 函数:

int status;
const auto& animal_ref = *animal;
const auto name = abi::__cxa_demangle(typeid(animal_ref).name(), 0, 0, &status);
cout << name << " makes sound: " << animal->makeSound() << endl;
Dog makes sound: Bark
Cat makes sound: Meow

除非为了更好地理解 RTTI 或出于调试目的而提出这个问题,否则我仍然强烈建议您重新考虑您的方法。这不是您的代码应该依赖的。

(是的,从技术上讲,即使是拆解可能还不够,并且名称可能会在调用之间发生变化。在我使用的实现中,这从未发生过。在我们谈论猫叫喵的时候,这更像是一种技术性比实际问题。)


推荐阅读