二十三. 运行时类型识别
● 定义
运行时类型识别(Run-time Type Identification, RTTI) |
通过RTTI, 程序能够使用基类的指针或引用来检查(check)这些指针或引用所指对象的实际派生类型.
C++通过下面两个操作符提供RTTI: ① typeid操作符, 返回指针或引用所指对象的实际类型; ② dynamic_cast操作符, 将基类类型的指针或引用安全地转换为派生类型的指针或引用. |
● 基类指针访问子类的特有成员函数
#include <iostream> using namespace std;
class Base { public: virtual char* GetName()=0; };
class Bint:public Base { public: char * GetName() { return "Bint";} int GetInt() { return 1;} };
class BString:public Base { public: char* GetName() { return "BString";} char* GetString() { return "Hello";} };
int main(int argc, char* argv[]) { Base* B1 = new Bint(); //也可以写成Base* B1 = (Base*)new Bint(); 但这里的(Base*)其实是多余的 printf(B1->GetName()); printf("\n");
Bint *B2= static_cast<Bint*>(B1); //下面要用基类指针B1来访问子类Bint的特有方法GetInt(), 我们首先要将B1静态转换为Bint型 if(B2) printf("%d", B2->GetInt()); printf("\n");
Base * C1 = new BString(); printf(C1->GetName()); printf("\n");
BString *C2 = static_cast<BString *>(C1); if(C2) printf(C2->GetString()); printf("\n"); return 0; }
|
● RTTI与虚继承
如果使用了虚继承, 将子类对象的地址赋值给基类指针, 此时, 基类指针仍可识别为它所指的子类对象的实际类型. ※ RTTI (Runtime Type Identification) 运行时类型识别 typeid 是一个用于运行时类型识别的操作符, 它返回的是type_info类型的常引用, type_info是C++标准库的一个类. 使用typeid注意使用头文件typeinfo.h |
#include <iostream> #include <typeinfo>
using namespace std;
class Animal { public: virtual void display(){} };
class Cow:public Animal{};
class Dog:public Animal {};
int main(){ Animal *anm; Cow cw; Dog dg;
cout << "type of anm is : "<<typeid(anm).name()<<endl; cout << "type of cw is : "<<typeid(cw).name()<<endl; cout << "type of dg is : "<<typeid(dg ).name()<<endl;
// initializing base pointer with the address of a derived class object; anm = &cw; cout<<"type of *anm when pointing to cw is: "<<typeid(*anm).name()<<endl; anm = &dg; cout<<"type of *anm when pointing to dg is: "<<typeid(*anm).name()<<endl; system("PAUSE"); return 0; } |
● 标准C++的类型转换符
对于强制类型转换的风险, 最好的解决方法就是不要使用C风格的强制类型转换,而是使用标准C++的类型转换符:static_cast、dynamic_cast、reinterpret_cast、和const_cast。 用法: dynamic_cast < typeid > ( expression ); 以此类推 ※ 所有的cast操作符都是针对 指针或引用 来转换的,不能对普通类型进行操作. ① static_cast 进行上行转换(把子类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查(check),所以是不安全的。
② dynamic_cast 进行上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全
③ reinterpret_cast 将某一类型转换为原来的类型 #include "iostream.h"
int main(int argc, char* argv[]) { int n = 97; char p[4] = {0}; p[0] = (char)n; //将整型的n强转为字符型, 并作为数组p的第0个元素 cout<<p<<endl; int *f = reinterpret_cast<int*>(&p); //将p(代表了数组p的第0个元素)的地址转换成原来的整型指针 cout<<*f<<endl; return 0; }
④const_cast 强制将一个const变量(只读变量)变成一个非const的等价形式(即并不就是把某个const变量转换为一般的变量) #include <iostream> using namespace std;
int main(int argc, char* argv[]) { const int a=1; int* b=const_cast<int*>(&a); //不能是int b=const_cast<int>(a) * b=2; //const变量a的等价形式是*b cout<<* b<<endl; } |
● 数组和向量
在计算机领域, 一维数组(single-dimensional array)=向量(能自己管理内存,又不限长度); 二维数组(2-dimensional array)=矩阵 ※"之所以选择'vector'这个名字,是因为Alex Stepanov作为C++标准库的设计者当初在寻找一个可以与内置数组类型区分开来的名字的时候,使用了"向量"这个表示; 他现在承认这确实是个错误,因为数学家们通常使用"向量"来表示一个定长的序列。 |
● 向量
向量的定义方式有四种: vector<int> a(10); vector<int> b(10, 1); vector<int> c(b); vector<int> d(b.begin(), b.begin()+3); 如果要输出向量中的所有元素, 可以有两种循环控制方式: //第一种: for (int i=0; i<a.size(); i++) cout<<a[i]<<" "; //第二种: for (vector<int>::iterator it=a.begin(); it!=a.end(); ++it) cout<<*it<<" "; |