typeid
xuqing-ICT 2014-05-04 22:22:07 19592 收藏 17
man_of_sillyy 2016-06-26 14:07:43 20106 收藏 5
简介
typeid是C++的关键字之一,等同于sizeof这类的操作符。typeid操作符的返回结果是名为type_info的标准库类型的对象的引用。
在将该操作符之前,不得不提的是RTTI(Run-Time Type Identification,运行时类型识别),其实就是说在运行期得到对象的实际的类型。这立刻使我们想到了"可以通过基类的指针和引用可以指向实际的派生类型"。
**type_info,**这是定义在标准库的一个类类型class type_info; 值得一提的是,该类的拷贝构造函数以及赋值操作符被定义为private,这是禁止复制该类型的对象。创建type_info对象的唯一方法,便是调用typeid操作符。
该类中最常用的成员函数name函数,该函数的返回类型是一个C风格的字符串,用于表示类型的id。
该函数同样是一个异常安全的函数,即不抛出异常。
(1) 当typeid操作符的操作数是不带有虚函数的类类型时,typeid操作符会指出操作数(左边声明)的类型,而不是底层对象的类型。
(2) 如果typeid操作符的操作数是至少包含一个虚拟函数的类类型时,并且该表达式是一个基类的引用,则typeid操作符指出底层对象的派生类类型(而不是基类类型)。
实例
常用类型int…
对于在编译器与运行期类型一直的对象,typeid同样适用,比如内置类型。
例如下面的代码:
int main()
{
int iVal;
double dVal;
cout << typeid(iVal).name() << endl;
cout << typeid(dVal).name() << endl;
return 0;
}
上述代码用于获取 int 以及 double 的类型id。
注:在不同的编译器设置下,输出的结果可能不同。
类class…
如果表达式的类型是类类型且至少包含有一个虚函数,则typeid操作符返回表达式的动态类型,需要在运行时计算;否则,typeid操作符返回表达式的静态类型,在编译时就可以计算。
#define OUTPUT(f) cout << #f << "t: " << typeid(f).name() << endl;
class BaseA {};
class DeriveA: public BaseA {};
class BaseB
{
virtual void f(){}
};
class DeriveB: public BaseB {};
int _tmain(int argc, _TCHAR* argv[])
{
cout << "-------直接处理类名-------" <<endl;
OUTPUT(BaseA);
OUTPUT(DeriveA);
OUTPUT(BaseB);
OUTPUT(DeriveB);
cout << endl << "-------基类不含虚函数-------" <<endl;
BaseA baseA;
DeriveA deriveA;
OUTPUT(baseA);
OUTPUT(deriveA);
BaseA* pa;
pa = &baseA;
OUTPUT(*pa);
OUTPUT(pa);
pa = &deriveA;
OUTPUT(*pa);
OUTPUT(pa);
cout << endl << "-------基类含有虚函数-------" <<endl;
BaseB baseB;
DeriveB deriveB;
OUTPUT(baseB);
OUTPUT(deriveB);
BaseB* pb;
pb = &baseB;
OUTPUT(*pb);
OUTPUT(pb);
pb = &deriveB;
OUTPUT(*pb);
OUTPUT(pb);
}
static_cast和dynamic_cast
ShyHerry 2018-04-06 22:59:50 71964 收藏 253
注:从图中可以看出,派生类不仅有自己的方法和属性,同时它还包括从父类继承来的方法和属性。当我们从派生类向基类转换时,不管用传统的c语言还是c++转换方式都可以百分百转换成功。但是可怕是向下转换类型,也就是我们从基类向派生类转换,当我们采用传统的C语言和c++转换时,就会出现意想不到的情况,因为转换后派生类自己的方法和属性丢失了,一旦我们去调用派生类的方法和属性那就糟糕了,这就是对类继承关系和内存分配理解不清晰导致的。好在c++增加了static_cast和dynamic_cast运用于继承关系类间的强制转化。
static_cast和dynamic_cast使用方式
static_cast< new_type >(expression)
dynamic_cast< new_type >(expression)
备注:new_type为目标数据类型,expression为原始数据类型变量或者表达式。
尽量少使用转型操作,尤其是dynamic_cast,耗时较高,会导致性能的下降,尽量使用其他方法替代。
static_cast
static_cast相当于传统的C语言里的强制转换,该运算符把expression转换为new_type类型,用来强迫隐式转换如non-const对象转为const对象,编译时检查,用于非多态的转换,可以转换指针及其他,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:
①用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。
进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。
③把空指针转换成目标类型的空指针。
④把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expression的const、volatile、或者__unaligned属性
(1) 基本类型数据转换举例如下:
char a = 'a';
int b = static_cast<char>(a);//正确,将char型数据转换成int型数据
double *c = new double;
void *d = static_cast<void*>(c);//正确,将double指针转换成void指针
int e = 10;
const int f = static_cast<const int>(e);//正确,将int型数据转换成const int型数据
const int g = 20;
int *h = static_cast<int*>(&g);//编译错误,static_cast不能转换掉g的const属性
(2) 类上行和下行转换:
class Base {};
class Derived : public Base {}
Base *pB = new Base();
if(Derived *pD = static_cast<Derived *>(pB))//下行转换是不安全的(坚决抵制这种方法)
{}
Derived *pD = new Derived();
if(Base *pB = static_cast<Base *>(pD))//上行转换是安全的
{}
dynamic_cast
有人说dynamic_cast是强制类型转换,转换成需要的类型指针,前提是你要知道这个对象的继承方式。dynamic_cast可以用"是否可以安全地将对象的地址赋值给特定类型的指针"这样的描述。知道类型后,就可以调用这个类型特有的方法了。通过dynamic_cast运算符就可以保证类型安全了。
dynamic_cast能够在类层次中进行向上转换(类之间是is-a关系),而不允许其他装换。其他转换返回NULL指针,比如向下转换。
(wb175208 2018-09-29 11:55:43 2523 收藏 5)
转换方式:
dynamic_cast< type >(e) type必须是一个类类型且必须是一个有效的指针
dynamic_cast< type& >(e) type必须是一个类类型且必须是一个左值
dynamic_cast< type&& >(e) type必须是一个类类型且必须是一个右值*
e的类型必须符合以下三个条件中的任何一个:
1、e的类型是目标类型type的公有派生类
2、e的类型是目标type的共有基类
3、e的类型就是目标type的类型。
如果一条dynamic_cast语句的转换目标是指针类型并且失败了,则结果为0。如果转换目标是引用类型并且失败了,则dynamic_cast运算符将抛出一个std::bad_cast异常(该异常定义在typeinfo标准库头文件中)。e也可以是一个空指针,结果是所需类型的空指针。
dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换(cross cast)。
在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。dynamic_cast是唯一无法由旧式语法执行的动作,也是唯一可能耗费重大运行成本的转型动作。
(1) 指针类型
举例,Base为包含至少一个虚函数的基类,Derived是Base的共有派生类,如果有一个指向Base的指针bp,我们可以在运行时将它转换成指向Derived的指针,代码如下:
if(Derived *dp = dynamic_cast<Derived *>(bp)){
//使用dp指向的Derived对象
}
else{
//使用bp指向的Base对象
}
值得注意的是,在上述代码中,if语句中定义了dp,这样做的好处是可以在一个操作中同时完成类型转换和条件检查两项任务。
(2) 引用类型
因为不存在所谓空引用,所以引用类型的dynamic_cast转换与指针类型不同,在引用转换失败时,会抛出std::bad_cast异常,该异常定义在头文件typeinfo中。
void f(const Base &b){
try{
const Derived &d = dynamic_cast<const Base &>(b);
//使用b引用的Derived对象
}
catch(std::bad_cast){
//处理类型转换失败的情况
}
}