• 【运行时的类型识别】


    RTTI (运行时类型识别 ) :允许"用指向基类的指针或引用来操纵对象" 的程序能够获取到," 这些指
    针或引用所指对象" 的实际派生类型。
    在C++中为了支持 RTTI 提供了两个操作符:

    1. typeid 操作符,它在程序中可用于获取一个表达式的类型 ;
      查询类型的信息, 类型身份认证。它指出指针或引用指向对象的实际派生类型。
    2. dynamic_cast 操作符可以用来把一个类类型对象的指针,转换成同一类层次结构中的其他类的指针 ,同时也可以用它把一个类类型对象的左值,转换成同一类层次结构中其他类的引用。
      dynamic_cast 和 typeid 操作符的操作数的类型 ,必须是带有一个或多个虚拟函数的类类型。 即对于带有虚拟函数的类而言 RTTI 操作符是运行时刻的事件 ,而对于其他类而言,它只是编译时刻的事件。

    重点:
    在所有情况下, typeid 都忽略顶层的 cv 限定符 !!!!!。

    1. typeid 操作符(运行时的类型识别)

    1.typeid() 指出指针或引用指向对象的实际派生类型。

    class Object
    {
    	int val;
    public:
    	Object(int x=0) :val(x){}
    	~Object() {}
    	 virtual void fun(){}
    };
    int main()
    {
    	Object* op = nullptr;
    	Object obja;
    	cout << typeid(op).name() << endl; //class Object *
    	cout << typeid(obja).name() << endl;//Object
    	cout << typeid(*op).name() << endl;//error //op没有指向到派生类对象
    	return 0; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    cout<派生类对象,编译报错。

    我们把fun()函数的virtual 关键字去掉看看会发生什么:

    class Object
    {
    	 void fun(){}
    };
    int main()
    {
    	Object* op = nullptr;
    	Object obja;
    	cout << typeid(*op).name() << endl;//ok //class object
    	return 0; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述
    为什么去掉了virtual关键字打印的是object类型?
    我们猜测,去掉了关键字的typeid()是在编译时类型识别,而不是在运行时。
    2.忽略CV限定符
    当typeid()识别指针和引用时,const 不忽略,可以显示出来;当typeid()指向对象时,将忽略CV限定符(不显示)。

    class Object
    {
    public:
    	Object(int x=0) :val(x)
    	{}
    	~Object() {}
    	  virtual void fun(){}
    };
    class Base :public Object 
    {
    public:
    	virtual void fun() {}
    };
    int main()
    {
    	const Base base1;
    	const Object* ip = nullptr;
    	const Object* op = &base1;
    	 Object obja;
    	cout << typeid(*op).name() << endl; //class
    	cout << typeid(obja).name() << endl;
    	cout << typeid(ip).name() << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这里插入图片描述


    一个带有函数模板的小例子:

    class Object
    {
    	int val;
    public:
    	Object(int x=0) :val(x)
    	{}
    	~Object() {}
    	  virtual void fun()
    	{
    	}
    
    };
    class Base :public Object 
    {
    public:
    	virtual void fun() {}
    };
    template<class T>
    void func(T& x)
    {
    	cout << typeid(x).name();//class object
    	T y;
    	cout << typeid(y).name();
    }
    int main()
    {
    	Object obja(10);
    	Object objb(20);
    	func(obja);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在这里插入图片描述

    以下程序的问题?

    template<class T>
    void func(T& x)
    {
    
    	cout << typeid(x).name();
    	T y;//error  const 常性类型必须要初始化
    	cout << typeid(y).name();
    }
    int main()
    {
    	const int a = 10;
    	func(a);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    4 . dynamic_cast

    语法:dynamic_cast < typen_ame> ( expression )
    说明:dynamic_cast 操作符, 它允许在运行时刻进行类型转换 ,从而使程序能够在一个类层次结构中安全地转换类型, 把基类指针转换成派生类指针,或把指向基类的左值转换成派生类的引用
    必须公有继承基类要有虚函数
    特点:

    1. 与C++支持的其他强制转换不同的是, dynamic_cast 是在运行时执行的类型转换。
    2. 如果针对指针类型的 dynamic_cast 失败, 则dynamic_cast 的结果是 nullptr。
    3. 如果针对引用类型的 dynamic_cast 失败, 则 dynamic_cast 会抛出一个异常。
    4. 在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。
    5. 在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。

    1.下行转换(主要)

    会出现一个什么潜在的危险?几个错误和一个正确的例子(把person*p= 那行代码指向改改再试试)

    在这里插入图片描述
    那么动态转换的原理是什么?

    在这里插入图片描述

    在这里插入代码片
    
    • 1

    2.上行转换

    在这里插入图片描述
    都是静态转换
    不用转换关键字也可以。

  • 相关阅读:
    今天的码农女孩用react写了轮播图以及组件之间的不同之处
    华为交换机配置ssh登录远程管理交换机
    深入理解Linux内核页表映射分页机制原理
    Linux常用命令详解
    【JS】Chapter13-构造函数&数据常用函数
    【论文笔记】面向地下空间探测的移动机器人定位与感知方法
    【Qt】Qt修改Linux系统时间,C语言修改Linux系统时间
    python-opencv边缘检测与人脸检测应用
    【Java技术路线】7. 异常与调试
    Android 如何在Android studio中快速创建raw和assets文件夹
  • 原文地址:https://blog.csdn.net/lmy347771232/article/details/126114435