C++之RTTI机制

在C++中,只有类中包含了虚函数时才会启用RTTI机制,也就是当存在多态时才会存在RTTI机制,因为不存在多态的话在编译阶段既可以确定类型信息。

C++中,只有类中包含了虚函数时才会启用RTTI机制,也就是当存在多态时才会存在RTTI机制,因为不存在多态的话在编译阶段既可以确定类型信息。

RTTI简介

RTTI(Runtime Type Indentification) 即运行阶段类型识别。这是 C++新引进的特性之一。RTTI旨在为程序在运行阶段确定对象的类型提供一种标准方式。

这RTTI听起来是不是有点java中反射的味道?大差不差...

C++之RTTI机制

在C++中,只有类中包含了虚函数时才会启用RTTI机制,也就是当存在多态时才会存在RTTI机制,因为不存在多态的话在编译阶段既可以确定类型信息。

运行时类型识别(RTTI)功能主要由以下两个运算符实现:

  • typeid运算符,用于返回表达式的类型
  • dynamic_cast运算符,用于将基类的指针或引用安全地转换成派生类的指针

RTTI与dynamic_cast

我们知道C++中的多态是基于虚函数的方式实现的,而含有虚函数的类都会有一个对应的虚函数表,而这个虚函数表会存有相关类型的type_info的地址, 因而可以说dynamic_cast为RTTI的一个应用。

因为dynamic_cast使用RTTI,所以它在转换的过程中是可靠的,只有进行转换的指针确实是指向指定的类型时才会转换成功,否则就会转换失败,返回空指针。

例如以下的例子,第27行和第28行通过new不同的对象类型,会影响到第29行dynamic_cast的转换结果:

#include <iostream>
class Base {
public:
    Base(){

    }
    virtual ~Base() {

    }
    virtual void f(){
        std::cout << "Base f" << std::endl;
    }
};

class Derived :public Base {
public:
    Derived(){

    }
    virtual ~Derived() {}
    void f() override{
        std::cout << "Derived f" << std::endl;
    }
};

int main() {
//    Base *base = new Base;
    Base *base = new Derived;
    Derived *derived = dynamic_cast<Derived*>(base);
    if(nullptr != derived){
        derived->f();
    } else{
        std::cout << "dynamic_cast null" << std::endl;
    }
    return 0;
}

RTTI与typeid

typeid当作用于指针时,返回的结果是该指针的静态编译时类型。typeid当作用于指针时,该指针必须是有效的,若是空指针,将返回bad_typeid异常。

typeid 运算符返回一个对type_info对象的引用,其中,type_info是在头文件 typeinfo 中定义的一个类。type_info类重载了==和 != 运算符,以便可以使用这些运算符来对类型进行比较。

通过typeid 运算符我们就可以判断一个指针指向的真实类似是否是派生类:

#include <iostream>
class Base {
public:
    Base(){

    }
    virtual ~Base() {

    }
    virtual void f(){
        std::cout << "Base f" << std::endl;
    }
};

class Derived :public Base {
public:
    Derived(){

    }
    virtual ~Derived() {}
    void f() override{
        std::cout << "Derived f" << std::endl;
    }
};

int main() {
    std::vector<Base*> vec;
    vec.emplace_back(new Base);
    vec.emplace_back(new Derived);
    for (auto base: vec) {
        std::cout << "clase Name:" << typeid(*base).name() << std::endl;
        if(typeid(*base) == typeid(Derived)){
            std::cout << "base的运行类型是Derived"  << std::endl;
        } else{
            std::cout << "base的运行类型是Base"  << std::endl;
        }
        // 调用f函数验证一下上面的打印是否正确
        base->f();
    }
    return 0;
}

运行结果打印:

C++之RTTI机制

RTTI运行结果打印

需要注意的是以上实例代码的第31和第32行,对于typeid运算符,typeid(*base)和typeid(base)它们得到的结果是不同的, typeid(*base)才能正确获得指针的类型。因为*base是指针的真实数据内容,而base只是一个指针。

按照这个原理表达式typeid(base)获得的类型永远是Base的指针,即使指针base指向的可能是派生类Derived,但typeid(base)也无法获得正确的类型, 务必要使用typeid(*base)。

©本文为清一色官方代发,观点仅代表作者本人,与清一色无关。清一色对文中陈述、观点判断保持中立,不对所包含内容的准确性、可靠性或完整性提供任何明示或暗示的保证。本文不作为投资理财建议,请读者仅作参考,并请自行承担全部责任。文中部分文字/图片/视频/音频等来源于网络,如侵犯到著作权人的权利,请与我们联系(微信/QQ:1074760229)。转载请注明出处:清一色财经

(0)
打赏 微信扫码打赏 微信扫码打赏 支付宝扫码打赏 支付宝扫码打赏
清一色的头像清一色管理团队
上一篇 2023年11月23日 17:07
下一篇 2023年11月23日 17:07

相关推荐

发表评论

登录后才能评论

联系我们

在线咨询:1643011589-QQbutton

手机:13798586780

QQ/微信:1074760229

QQ群:551893940

工作时间:工作日9:00-18:00,节假日休息

关注微信