用处:
typeid()函数主要用来获取对应类型或者变量的类型信息,其返回一个std::type_info的对象,这个对象中存放了对应类型的具体信息。
所以typeid()函数就是获取一个type_info的类型,然后可以通过此类型来获取到相应的类型信息。
type_info的声明
class type_info {
public:
virtual ~type_info();
bool operator==(const type_info& rhs) const;
bool operator!=(const type_info& rhs) const;
bool before(const type_info& rhs) const;
const char* name() const;
private:
// 私有构造函数、复制构造函数和赋值运算符,以防止直接创建和复制
type_info(const type_info&);
type_info& operator=(const type_info&);
};
这个类中你会发现内部有包含很多关于类型信息的操作函数。
1. name(); // 可以获取到对应类型信息的名字。2. 重载了比较运算符,可以对获取到的类型信息进行比较。
3. 主要的是,其赋值构造函数和有参构造函数,都设置为了私有的,在别的编译器实现可能会使用=delete删除掉,也就意味着我们没有办法使用type_info类定义对象,所以只有使用typeid才能够获取type_info类型的对象,来获取对应的信息。
注意: type_info类型和typeid的实现是基于编译器的,也就是说c++只是提出了基于语法的层面,对于具体的实现不同的编译器是不一样的,但是用法都是类似的。
typeid的具体使用:
首先说明,typeid的实现一般是基于虚函数的,当然是我们自己定义的类型,所以建议都使用虚函数。
原因是因为,基于c++的多态,虚函数会保存一个虚函数表的指针,虚函数表中会存储一个type_info的类型信息,但是至于存储在哪个位置,这是由编译器决定的,不同的编译器不一样,我们实际使用的时候没有必要关心。typeid就是借助虚函数表的机制可以判断出多态下父类指针指向的具体实际类型。具体其实如何得知的,我猜测,应该是当父类的指针指向子类对象实现多态的时候,其对应父类的type_info信息的类型就会修改为其指向的子类类型。(不一定正确)
其实原因就是在多态的实现过程中,可以获取到对应指针指向的实际类型。
定义一下三个类进行测试:
class People {
public:
People() = default;
virtual void write() {
std::cout << "People\n";
}
};
class Man : public People {
public:
Man() = default;
virtual void write() override {
std::cout << "Man\n";
}
};
class Woman : public People {
public:
Woman() = default;
virtual void write() override {
std::cout << "Woman\n";
}
};
int main(void) {
People* p1 = new People;
Man* m1 = new Man;
People* p2 = m1; // 使用多态
std::cout << typeid(p1).name() << std::endl; // class People*
std::cout << typeid(m1).name() << std::endl; // class Man*
std::cout << typeid(p2).name() << std::endl; // class People*
std::cout << typeid(*p2).name() << std::endl; // class Man
return 0;
}
对应的输出结果已经在函数调用之后了,记住typeid函数返回一个type_info类型的对象,但是我们不能使用这样的类型去接收,因为外部不可定义其对象,所以获取type_info类型只有通过typeid,所以获取之后直接使用这个对象。
代码中调用name()获取具体对象的类型。仔细看最后一个打印信息,p2是一个父类指针对象,所以其类型是父类指针类型,但是*p2则不一样,由于多态的实现,*p2就是p2指针实际指向的类型,此处为Man类型,所以我们使用typeid检测之后得到的就是Man类型的数据。
也可以用于一般类型:
std::cout << typeid(int) << std::endl; // int
类型进行比较
if(typeid(int) == typeif(float)){
}else{
}
我们可以直接使用==比较两个类型是否相同,相同执行一个分支否则执行另外一个分支,实现运行时类型检查,不同的类型情况进行不用的代码。
dynamic_cast借助typeid进行运行时类型检测
dynamic_cast是c++新增的类型强制转换,其主要用于继承系列的类型转换,成功返回转换后的指针,失败返回NULL。
其就是根据typeid获取对应的变量的实际类型,然后根据继承树来判断是否可以转换,子类转父类没问题,父类转子类会返回NULL。