个人生活分享

RTTI运行时类型识别

RTTI 运行时类型识别

  • 根据基类的指针或引用来获得该指针或引用所指的对象的实际类型

  • 通过typeid操作符识别出所有的基本类型的变量对应的类型

typeid​中的操作数是以下任意一种时,typeid​需要在程序运行时推算类型,因为其操作数的类型在编译时期是不能被确定的:

  • 一个指向含有多态的类对象的指针的解引用
  • 一个指向含有多态的类对象的引用
#include <iostream>
#include <string>
#include <vector>
#include <typeinfo>
#include <cxxabi.h>

const char* TypeToName(const char* name)
{
    const char* __name = abi::__cxa_demangle(name, nullptr, nullptr, nullptr);
    return __name;
}
// 单纯虚继承是无法体现出多态的,尽管它也会生成对应的虚表,要真正实现多态只能依靠虚函数来实现
class A
{
public:
    void print()
    {
        std::cout << "A" << std::endl;
    }

    int a;
};

class B : virtual public A
{
public:
    void print()
    {
        std::cout << "B" << std::endl;
    }

    int b;
};

class C : virtual public A
{
public:
    void print()
    {
        std::cout << "C" << std::endl;
    }

    int c;
};

class D : public B, public C
{
public:
    void print()
    {
        std::cout << "D" << std::endl;
    }

    int d;
};

int main(int argc, char* argv[])
{
    D d;
    A* a_ptr = &d;
    B* b_ptr = &d;
    C* c_ptr = &d;

    std::cout << TypeToName(typeid(d).name()) << std::endl;
    std::cout << TypeToName(typeid(*a_ptr).name()) << std::endl;
    std::cout << TypeToName(typeid(*b_ptr).name()) << std::endl;
    std::cout << TypeToName(typeid(*c_ptr).name()) << std::endl;
}

手动实现

    long long* vtbl_A = (long long*)*(long long*)a_ptr;
    std::cout << ((std::type_info*)*(vtbl_A - 1))->name() << std::endl << std::endl;