运行时类型识别(RTTI)

运行时类型识别(RTTI)#

RTTI(Run-Time Type Identification)允许程序在运行时获取对象的类型信息,主要包括 typeid 运算符和 dynamic_cast 运算符。

Note

注意:本站的 C/C++ 代码风格 参考 Google 风格约定禁止使用 RTTIdynamic_cast 有一定运行时开销, 大量使用通常意味着设计上的多态使用不当),本页仅作学习参考。

typeid#

#include <iostream>
#include <typeinfo>

using namespace std;

class Person {
protected:
    string name;

public:
    Person(string name = "") : name(name) {};
    virtual ~Person() {}
    string getInfo() { return name; }
};

class Student : public Person {
    string studentid;

public:
    Student(string name = "", string sid = "") : Person(name), studentid(sid) {};
    string getInfo() { return name + ":" + studentid; }
};

int main() {
    string s("hello");

    cout << "typeid.name of s           is " << typeid(s).name() << endl;
    cout << "typeid.name of std::string is " << typeid(std::string).name() << endl;
    cout << "typeid.name of Student     is " << typeid(Student).name() << endl;

    if (typeid(std::string) == typeid(s)) cout << "s is a std::string object." << endl;

    return 0;
}

多态与类型转换的陷阱#

下面的例子演示了 C 风格强制转换的危险性:把基类对象强行转换成派生类指针后调用虚函数,会产生未定义行为。 安全的做法是使用 dynamic_cast(配合虚函数)进行向下转换。

#include <iostream>

using namespace std;

class Person {
protected:
    string name;

public:
    Person(string name = "") : name(name) {};
    virtual ~Person() {}
    string getInfo() { return name; }
};

class Student : public Person {
    string studentid;

public:
    Student(string name = "", string sid = "") : Person(name), studentid(sid) {};
    string getInfo() { return name + ":(" + studentid + ")"; }
};

int main() {
    Person person("Yu");
    Student student("Sam", "20210212");
    Person* pp  = &student;
    Person& rp  = student;
    Student* ps = (Student*)&person; // danger!
    cout << "person.getInfo():" << person.getInfo() << endl;
    cout << "pp->getInfo():" << pp->getInfo() << endl;
    cout << "rp.getInfo():" << rp.getInfo() << endl;
    cout << "ps->getInfo():" << ps->getInfo() << endl; // danger if getInfo is not virtual

    char* p = (char*)100;
    // ps = dynamic_cast<Student*>(&person);
    // printf("address = %p\n", ps);
    // pp = dynamic_cast<Person*>(&student);
    // printf("address = %p\n", pp);
    return 0;
}

dynamic_cast 只能用于含虚函数的类层次,转换失败时:

  • 指针版本返回 nullptr

  • 引用版本抛出 std::bad_cast 异常。