首页 > 其他 > 详细

RTTI的介绍和使用

时间:2021-01-31 21:11:50      阅读:33      评论:0      收藏:0      [点我收藏+]

RTTI介绍及使用

什么是RTTI?

RTTI是[运行阶段类型识别](Runtime Type Identification) 。RTTI旨在为程序在运行阶段确定对象的类型提供一种标准的方式。很多类库已经为其对象提供了实现这种功能的方式,但由于c++内部不支持,因此各个厂商的机制通常互不兼容。

RTTI的用途

为何需要知道类型。可能希望调用类方法的正确版本,在这种情况下,只要该函数是类层次结构中所有成员都有的虚函数,则并不真正需要知道对象的类型。但派生对象可能包含不是继承而来的方法,在这种情况下,只有某些类型的对象可以使用该方法。也可能是出于调试的目的,想跟踪生成的对象的类型。对于后两种情况,RTTI提供解决方案。

RTTI的工作原理

C++有3个支持RTTI的元素。

  • 如果可能的话,dynamic_cast 运算符将使用一个指向基类的指针来生成一个指向派生类的指针:否则,该运算符将返回0——空指针。
  • typeid 运算符返回一个指出对象的类型的值。
  • type_info 结构存储了有关特定类型的信息。

警告:RTTI只适用于包含虚函数的类

1.dynamic_cast 运算符

dynamic_cast 不能回答“指针指向的是哪类对象”这样的问题,但能回答“是否可以安全地将对象的地址赋给特定的指针”这样的问题。

#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <ctime>

using std::cout;

class Grand
{
private:
	int hold;
public:
	Grand(int h = 0):hold(h){}
	virtual void Speak() const { cout << "I am a grand class!\n"; }
	virtual int value() const { return hold; }
};

class Superb :public Grand
{
public:
	Superb(int h = 0) :Grand(h){}
	void Speak() const { cout << "I am a Superb class!\n"; }
	virtual void Say() const { cout << "I hold the superb value of " << value() << "!\n"; }
};

class Magnificent :public Superb
{
private:
	char ch;
public:
	Magnificent(int h = 0, char c = ‘A‘) :Superb(h), ch(c) {}
	void Speak() const { cout << "I am a magnificent class !\n"; }
	void Say() const { cout << "I hold the character " << ch << " and the integer " << value() << "!\n"; }
};

Grand *GetOne();

Grand *GetOne()
{
	Grand *p = nullptr;
	switch (std::rand() % 3)
	{
	case 0:
		p = new Grand(std::rand() % 100);
		break;
	case 1:
		p = new Superb(std::rand() % 100);
		break;
	case 2:
		p = new Magnificent(std::rand() % 100, ‘A‘ + std::rand() % 26);
		break;
	default:
		break;
	}
	return p;
}

int _tmain(int argc, _TCHAR* argv[])
{
	std::srand(std::time(0));
	Grand *pg;
	Superb *ps;
	for (int i = 0; i < 5; i++)
	{
		pg = GetOne();
		pg->Speak();
		if (ps = dynamic_cast<Superb *>(pg))
			ps->Say();
	}
	return 0;
}

2.typeid 运算符和type_info类

typeid 运算符使得能够确定两个对象是否为同种类型。它可以接受两种参数:

  • 类名;
  • 结果为对象的表达式。

typeid 运算符返回一个对 type_info 对象的引用。type_info 类的实现随厂商而异,担包含一个name() 成员,该函数返回一个随实现而异的字符串:通常是类的名称。

#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <ctime>

using std::cout;

class Grand
{
private:
	int hold;
public:
	Grand(int h = 0):hold(h){}
	virtual void Speak() const { cout << "I am a grand class!\n"; }
	virtual int value() const { return hold; }
};

class Superb :public Grand
{
public:
	Superb(int h = 0) :Grand(h){}
	void Speak() const { cout << "I am a Superb class!\n"; }
	virtual void Say() const { cout << "I hold the superb value of " << value() << "!\n"; }
};

class Magnificent :public Superb
{
private:
	char ch;
public:
	Magnificent(int h = 0, char c = ‘A‘) :Superb(h), ch(c) {}
	void Speak() const { cout << "I am a magnificent class !\n"; }
	void Say() const { cout << "I hold the character " << ch << " and the integer " << value() << "!\n"; }
};

Grand *GetOne();

Grand *GetOne()
{
	Grand *p = nullptr;
	switch (std::rand() % 3)
	{
	case 0:
		p = new Grand(std::rand() % 100);
		break;
	case 1:
		p = new Superb(std::rand() % 100);
		break;
	case 2:
		p = new Magnificent(std::rand() % 100, ‘A‘ + std::rand() % 26);
		break;
	default:
		break;
	}
	return p;
}


int _tmain(int argc, _TCHAR* argv[])
{
	std::srand(std::time(0));
	Grand *pg;
	Superb *ps;
	for (int i = 0; i < 5; i++)
	{
		pg = GetOne();
		cout << "Now processing type " << typeid(*pg).name() << "!\n";
		pg->Speak();
		if (ps = dynamic_cast<Superb *>(pg))
			ps->Say();
		if (typeid(Magnificent) == typeid(*pg))
			cout << "Yes, you are really magnificent!\n";
	}
	return 0;
}

3. 误用RTTI 的例子

程序的核心代码
Grand *pg;
Superb *ps;
for(int i = 0; i < 5; i++)
{
    pg = GetOne();
    pg->Speak();
    if(ps = dynamic_cast<Superb *>(pg))
        ps->Say();
}
通过放弃使用dynamic_cast和虚函数,而是用typeid,可以将上树代码重新编写为:
Grand *pg;
Superb *ps;
Magnificent *pm;
for(int i = 0; i < 5; i++)
{
    pg = GetOne();
    if(typeid(Magnificent) == typeid(*pg))
    {
        pm = (Magnificent *)pg;
        pm->Speak();
        pm->Say();
    }
    else if(typeid(Superb) == typeid(*pg))
    {
        ps = (Superb *)pg;
        ps->Speak();
        ps->Say();
    }
    else
        pg->Speak();
}
放弃使用dynamic_cast和虚函数后代码更冗长,显式的指定各个类存在严重的缺陷。

提示:如果发现在扩展的if else 语句系列中使用了typeid,则应该考虑使用虚函数和dynamic_cast.

RTTI的介绍和使用

原文:https://www.cnblogs.com/sunyichao/p/14353355.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!