1. 类型识别
(1)在面向对象中可能出现下面的情况
①基类指针指向子类对象
②基类引用成为子类对象的别名
▲静态类型——变量(对象)自身的类型(定义变量类型时类型或参数类型)
▲动态类型——指针(引用)所指向的对象的实际类型
(2)基类指针转子类指针:
①示例:Derived* d = static_cast<Derived*>(pBase); //危险的转换方式
②问题:不安全,基类指针是否可以强制类型转换为子类指针取决动态类型。
2. 利用多态获取动态类型
(1)解决方案
①在基类中定义虚函数,并返回具体的类型信息
②所有的派生类都必须实现类型相关的虚函数
③每个类中的类型虚函数都需要不同的实现
【编程实验】动态类型识别 66-1.cpp
#include <iostream> #include <string> using namespace std; class Base { public: //在基类中提供个用来判断类型的虚函数 //并且所有的派生类中都必须实现这个函数 virtual string type() { return "Base"; //手动返回一个用于识别的标识符 } }; class Derived : public Base { public: string type() { return "Derived"; } void print() { cout << "I'm a Derived." << endl; } }; class Child : public Base { public: string type() { return "Child"; } }; void test(Base* b) { //危险的转换方式。因为b可能实际类型可能不是Derived的类型 //Derived* d = static_cast<Derived*>(b); if(b->type() == "Derived") { Derived* d = static_cast<Derived*>(b); d->print(); } //如果类中没有虚函数表,则调用dynamic_cast会直接报错,编译不过。 //当父、子类没有继承关系时,dynamic_cast返回false,否则会转换后 //实际对象的地址 cout << dynamic_cast<Derived*>(b) << endl; } int main() { Base b; Derived d; Child c; test(&b); //Base与Base没有继承关系,dynamic_cast返回false test(&d); //Derived与Base有继承关系,dynamic_cast转换后对象的地址 test(&c); //Child与Derived没有继承关系,返回false return 0; }
运行结果:
(2)多态解决方案的缺陷
①必须从基类开始提供类型虚函数
②所有的派生类都必须重写类型虚函数
③每个派生类的类型名必须唯一
3. 类型识别关键字:typeid获取类型信息
(1)typeid关键字
-
typeid关键字返回对应参数的类型信息
-
typeid返回一个type_info类的对象
-
当typeid的参数为NULL时抛出异常
-
包含头文件#include<typeinfo>
(2)typeid关键字的使用
int i = 0; const type_info& tiv = typeid(i); //得到变量i的类型信息 const type_info& tii = typeid(int); //得到int类型信息
(3)typeid的注意事项
①当参数为类型时:返回静态类型信息
②当参数为变量时:
A.不存在虚函数表时:返回静态类型信息
B.存在虚函数表时:返回动态类型信息
【编程实验】typeid类型识别 66-2.cpp
#include <iostream> #include <string> #include <typeinfo> //for typeid using namespace std; class Base { public: virtual ~Base(){} }; class Derived : public Base { public: void print() { cout << "I'm a Derived." << endl; } }; void test(Base* b) { //const type_info& tb = typeid(b); //判断b的类型,Base*或Derived* const type_info& tb = typeid(*b); //判断对象的类型 cout << tb.name() << endl; } int main() { int i = 0; const type_info& tiv = typeid(i); //判断变量的类型 const type_info& tii = typeid(int); //判断类的类型 cout << (tiv == tii) << endl; //相等 Base b; Derived d; test(&b); test(&d); return 0; }
运行结果:g++下类名前面的数字表示类名的长度
4. 小结
(1)C++中有静态类型和动态类型的概念
(2)利用多态能够实现对象的动态类型识别
(3)typeid是专用于类型识别的关键字
(4)typeid能够返回对象的动态类型信息