运算符typeid返回包含操作数数据类型信息的type_info对象的一个引用,信息中包含数据类型的名称,要使用typeid,程序中必须包含头文件<typeinfo>
其中type_info重载了操作符==,!=分别用来比较是否相等,不等,函数name()返回类型名称.type_info的拷贝和赋值均是私有的,故不可拷贝和赋值
使用实例:
cout << typeid(int).name() << endl;
cout << typeid(char).name() << endl;
cout << typeid(long).name() << endl;
void(*pf)(int);
cout << typeid(pf).name() << endl;
使用条件:在多态体系中,使用时必须解引用指向类的指针,同时,类必须使用虚析构
class A {
public:
virtual ~A(){} //使用虚析构
};
class B :public A {
};
class C :public A {
};
int main() {
A* pa = new B;
B* pb = new B;
//cout << typeid(pa).name() << endl; //这样使用是错误的
if(typeid(*pa) == typeid(*pb)) //用来进行判别
cout<<"same class"<<endl;
cout << typeid(*pa).name() << endl;
}
注意点:
1.确保类中使用了虚析构
2.不要将typeid作用于指针,如果作用于指针不管赋给的是什么类,比较时typeid的结果都是指针,没有区别,会出错
所有要作用于引用或者指针解引用
3.typeid是一个运算符,不是函数,且其结果不能被保存,如果要保存其结果,使用.name()函数
4.typeid作用于对象且指针为空时,会抛出bad_typeid异常
dynamic_cast
赋值兼容层面的语义,即上转(upcast),不需要显示的转化(因为是安全的)
但如果要实现父类到子类的转化,则需要借助dynamic_cast(下转)
class A {
public:
virtual ~A(){} //使用虚析构
};
class B :public A {
};
class C :public A {
};
class D {
};
int main() {
B b;
A* pa = &b; //这是上转,是安全的
B* pb = dynamic_cast<B*>(pa); //安全地实现了下转
if (pb == nullptr) {
cout << "pb == nullptr" << endl;
}
else {
cout << "pb != nullptr" << endl;
}
D* pd = dynamic_cast<D*>(pa); //因为指向的是无关类,不安全,所有返回一个空指针
if (pd == nullptr) {
cout << "pb == nullptr" << endl;
}
else {
cout << "pb != nullptr" << endl;
}
system("PAUSE");
}
dynamic_cast会自动进行检测:
如果downcast是安全的(如果基类指针或者对象确实指向派生类对象),会传回适当转型过的指针
如果downcast是不安全的(如果基类指针或者对象没有指向派生类对象),会传回空指针
应用实例:发奖金
一个公司中有若干职位成员,如果我们要对指定的成员发工资,我们首先可以通过typeid判断员工属性,然后通过dynamic_cast下转调用该员工派生类中的发奖金函数:
(为什么要下转,假设基类中没有发工资函数,是派生类中新定义的,此时要将父类指针下转去调用这个函数)
Manager *pm = nullptr; //发奖金的对象
Employee* employeeList[] = { new Manager, new Technician, new SalesMan, new SaleManager, new SalesMan}; //赋值兼容
for (auto emp : employeeList) {
emp->init(); //类的识别:涨工资操作
if (typeid(*emp) == typeid(Manager)) {
cout << "发奖金" << endl;
if (pm = dynamic_cast<Manager*>(emp)) { //发工资函数为子类中新定义的,下转后,调用派生类中的发工资函数
pm->addSalary(5000);
}
}
emp->promote(); //晋升:重写父类函数
emp->calSalary(); //统计工资:重写父类函数
emp->disInfo(); //显示信息:重写父类函数
}