第三十九节 C++ 类型转换运算符 static_cast, dynamic_cast, reinterpret_cast, const_cast

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dddd0216/article/details/79964778
C++类型转换运算符:static_cast, dynamic_cast, reinterpret_cast, const_cast

使用格式: dest_type result = cast_type<dest_type> (objest_to_be_casted)

static_cast:  用途1: 在继承中,在编译阶段检查转换类型是否相关,若不相关,编译失败,可用于继承类的向上转换
                   用途2: 显示提醒程序员,这里进行了类型转换, int num = static_cast<int>(value);

dynamic_cast: 在运行阶段,检查转换类型是否相关,用于继承类的向下转换,可检测使用基类参数的对象,是否为此基类的派生类,若不是,返回NULL,用dynamic_cast时一定要检查返回的地址是否为NULL

reinterpret_cast: 强制类型转换

const_cast: 去除const限制

#include <iostream>
using namespace std;

class  Base {
public:
	/*实现多态*/
	virtual void getVesion() {
		cout << "The Base class getVesion()" << endl;
	}

	Base() { cout << "Base() constructor" << endl; }

	/*防止仅释放基类*/
	virtual	~Base() { cout << "~Base() deconstructor" << endl; }

};

class Derived : public Base {
public:
	void getVesion() {
		cout << "The Derived getVesion()" << endl;
	}

	Derived() {
		cout << "Detived() constrctor" << endl;
	}

	~Derived() { 
		cout << "~Detived() deconstrctor" << endl; 
		delete this;
	}
};

class Derived2 : public Base {
public:
	void getVesion() {
		cout << "The Derived2 getVesion()" << endl;
	}

	Derived2() {
		cout << "Detived2() constrctor" << endl;
	}

	~Derived2() {
		cout << "~Detived2() deconstrctor" << endl;
		delete this;
	}
};


class NotDerived {
public:
	void getVesion() {
		cout << "The NotDerived getVesion()" << endl;
	}

	NotDerived() {
		cout << "NotDerived() constrctor" << endl;
	}

	~NotDerived() {
		cout << "~NotDerived() deconstrctor" << endl;
		delete this;
	}
};

void VerifyObject(Base* input) {
	/*dynamic_cast检查两者是否有关系,即检查传入的是不是Derived对象,
	若是返回一个指针,若不是返回NULL*/
	if (dynamic_cast<Derived *> (input))  //向下转换,基类转派生类,安全的转换
		cout << "Is Derived" << endl;
	else
		cout << "Not Derived" << endl;
}

int main()
{
	Derived* isDerived = new Derived;
	Derived2* isDerived2 = new Derived2;
	NotDerived* notDetived = new NotDerived;
	
	cout << "---- static_cast ----" << endl;
	/*向上转换,可以使用static_cast,仅在编译阶段起作用,如下。*/
	Base* base = static_cast<Base*> (isDerived); //编译通过,类型相关,继承关系
	//Base* base = static_cast<Base*> (notDetived); //编译错误,类型不相关,不存在继承关系

	/*但是使用static_cast向下转换是不安全的转换,因为基类转成派生类对象,而派生类对象的某些方法可以没有实现,
	导致调用错误,但是由于存在继承关系使用static_cast进行向下转换可以编译通过的,但在运行阶段出问题。
	所以最好不要使用其进行向下转换
	*/

	cout << "---- dynamic_cast ----" << endl;
	VerifyObject(isDerived);
	VerifyObject(isDerived2);

	return 0;
}

output:

Base() constructor
Detived() constrctor
Base() constructor
Detived2() constrctor
NotDerived() constrctor
---- static_cast ----
---- dynamic_cast ----
Is Derived
Not Derived

阅读更多

reinterpret_cast,const_cast,static_cast,dynamic_cast 总结

10-24

reinterpret_cast,const_cast,static_cast,dynamic_cast 总结rnrnrn(一)、reinterpret_castrn rn 1、将一个类型指针转换为另一个类型指针,这种转换不修改指针变量值数据存放格式rn 2、只需在编译时重新解释指针的类型,它可以将指针转化为一个整型数但不能用于非指针的转换rnrndouble d=9.3;rndouble* pd = &d;rnint* pi = reinterpret_cast (pd);rnclass A;rnclass B;rnA* pa = new A;rnB* pb=reinterpret_cast(pa); //将pa 转为Brnlong j=reinterpret_cast (pa);//指针转换为整数rn int i=9;rn double x=reinterpret_cast(i); //reinterpret_cast不能用于非指针的转换rnrn(二)、const_cast rn 用法:const_cast< type-id > (exdivssion)rn 该运算符用来修改类型的const或volatile属性。rn rn 1.用于去除指针变量的常属性,将它转换为一个对应指针类型的普通变量,rn 2.反过来也可以将一个非常量指针转换为一个常量指针变量rn 3.它无法将一个非指针的常量转换为普通变量rnrnexample: const i=10;rn int j=const_cast(i); //无法转换rnconst int ppp=998;rnrn const int* pca=&ppp; rnint* p=const_cast(pca);//将它转换为一个对应指针类型的普通变量,去除了const;可以改成int *p=(int *)(pca);rnrnconst A* paa=new A;rnA * ppppa=const_cast (paa);//它转换为一个对应指针类型的普通变量,去除了const;rnrnint * pii=0;//反过来也可以将一个非常量指针转换为一个常量指针变量rnconst int* piiic=const_cast(pii);rnrn注意下列情况:rn const int a=1;rn int &ra=a;// 错rn int *pa=&a;//错rn const int &rb=b;//对rn const int *pb=&b;//对rn rn//////////////////////////////////////////////////////////////////////////////////rnrn(三)、static_castrnrn 1、用于转换基本类型和具有继承关系的类成员之间转换rn 2、static_cast不太用于指针类型的之间的转换,它的效率没有reinterpret_cast的效率高。而对于基本类型的转换是完全不行的,rn 像这样rn double aa=1.0;rn int *p=static_cast(&aa);rn 是不允许的。rnrnint in=99;rndouble dn=static_cast (in);//用于转换基本类型和具有继承关系的类新之间转换rnrnclass Base;rnclass derv:public Base;rnderv dd;rnBase bbbb=static_cast(dd);//具有继承关系的类新之间转换rn rn//static_cast不太用于指针类型的之间的转换,它的效率没有reinterpret_cast的效率高rnBase *pb1=new Base;rnderv *pder=static_cast(pb1);//基类转继承类rnderv* pder1=new derv;rnBase* pbase1=static_cast(pder1);//继承类指针转父类指针,此时pbase1返回NULL;若pder1不是指针,则也返回NULLrnrn注意:static_cast不能转换掉exdivssion的const、volitale、或者__unaligned属性。rn//////////////////////////////////////////////////////////////////////////rnrn(四)、dynamic_castrn rn 1.只能在继承类对象的指针之间或引用之间进行类型转换rn 2.这种转换并非在编译时,而是在运行时,动态的rn 3.没有继承关系,但被转换的类具有虚函数对象的指针进行转换rn 4、dynamic_cast具有类型检查的功能,在把子类的指针或引用转换成基类时,比static_cast更安全。rnrnderv* dp=new derv;rnBase* bv=dynamic_cast(dp);//继承类对象的指针之间进行类型转换rnrnderv dpp;//继承类对象引用之间进行类型转换rnBase &b=dynamic_cast(dpp);rnrnclass AAvirtual fun()rnvirtual ~AA();rnclass BB;rnrn//没有继承关系,但被转换的类具有虚函数对象的指针进行转换,编译可通过rnAA* pAA=new AA;rnBB* pBB=dynamic_cast(pAA);//rnrn//没有继承关系,被转换的类也没有有虚函数对象的指针进行转换,编译不能通过rnBB* pBBB=new BB;rnAA* pAAA=dynamic_cast(pBBB);rnrnreturn 1;rnrnrnrn//总结:rn//reinterpret_cast 将一个类型指针转换为另一个类型指针rn//const_cast 用于去除指针变量的常属性,将它转换为一个对应指针类型的普通变量,反过来也可以将一个非常量指针转换为一个常量指针变量rn//static_cast 用于转换基本类型和具有继承关系的类成员之间转换,不太用于指针类型的之间的转换rn//dynamic_cast 只能在继承类对象的指针之间或引用之间进行类型转换rn//以上只有dynamic_cast这种转换并非在编译时,而是在运行时,动态的。其它均在编译时rnrnrn

使用标准C++类型转换符:static_castdynamic_castreinterpret_cast、和const_cast

11-25

3.1 static_castrn用法:static_cast < type-id > ( expression ) rn该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:rn①用于类层次结构中基类和子类之间指针或引用的转换。rn  进行上行转换(把子类的指针或引用转换成基类表示)是安全的;rn  进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。rn②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。rn③把空指针转换成目标类型的空指针。rn④把任何类型的表达式转换成void类型。rnrn注意:static_cast不能转换掉expression的const、volitale、或者__unaligned属性。rnrnrn3.2 dynamic_castrn用法:dynamic_cast < type-id > ( expression )rn该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;rn如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。rnrndynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。rn在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;rn在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。rnclass Brnpublic:rn int m_iNum;rn virtual void foo();rn;rnrnclass D:public Brn public:rn char *m_szName[100];rn;rnrnvoid func(B *pb)rn D *pd1 = static_cast(pb);rn D *pd2 = dynamic_cast(pb);rnrnrn在上面的代码段中,如果pb指向一个D类型的对象,pd1和pd2是一样的,并且对这两个指针执行D类型的任何操作都是安全的;rn但是,如果pb指向的是一个B类型的对象,那么pd1将是一个指向该对象的指针,对它进行D类型的操作将是不安全的(如访问m_szName),rn而pd2将是一个空指针。rnrn另外要注意:B要有虚函数,否则会编译出错;static_cast则没有这个限制。rn这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表(rn关于虚函数表的概念,详细可见)中,只有定义了虚函数的类才有虚函数表,rn没有定义虚函数的类是没有虚函数表的。rnrn另外,dynamic_cast还支持交叉转换(cross cast)。如下代码所示。rnclass Arnpublic:rn int m_iNum;rn virtual void f()rn;rnrnclass B:public Arn;rnrnclass D:public Arn;rnrnvoid foo()rn B *pb = new B;rn pb->m_iNum = 100;rnrn D *pd1 = static_cast(pb); //compile errorrn D *pd2 = dynamic_cast(pb); //pd2 is NULLrn delete pb;rnrnrn在函数foo中,使用static_cast进行转换是不被允许的,将在编译时出错;而使用 dynamic_cast的转换则是允许的,结果是空指针。rnrnrn3.3 reinpreter_castrn用法:reinpreter_cast (expression)rntype-id必须是一个指针、引用、算术类型、函数指针或者成员指针。rn它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,rn在把该整数转换成原类型的指针,还可以得到原先的指针值)。rnrn该运算符的用法比较多。rnrn3.4 const_cast rn用法:const_cast (expression)rn该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。rn常量指针被转化成非常量指针,并且仍然指向原来的对象;rn常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。rnrnVoiatile和const类试。举如下一例:rnclass Brnpublic:rn int m_iNum;rnrnvoid foo()rn const B b1;rn b1.m_iNum = 100; //comile errorrn B b2 = const_cast(b1);rn b2. m_iNum = 200; //finernrn上面的代码编译时会报错,因为b1是一个常量对象,不能对它进行改变;rn使用const_cast把它转换成一个常量对象,就可以对它的数据成员任意改变。注意:b1和b2是两个不同的对象。rnrnrnrnstatic_cast用于内建数据类型之间的转型。 rnreinterpret_cast用于对变量重新进行二进制解释,因此它的转型结果是编译器实现相关(implementation-dependent)的,不是可移植的,一般在实践中,只有迫不得已,才使用这种转型。例如直接将整数常量转型为某个自定义的struct类型,驱动程序的编写中常常使用这种技术。 rnrn另外还有两个: rndynamic_cast用于在继承体系中进行安全的向下转型(downcast),也就是从基类指针/引用向派生类指针/引用的转型。 rnconst_cast用于取消变量的常量性修饰。 rnrnrn本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zxpost1927/archive/2008/05/24/2477662.aspx

总结C++中的所有强制转换函数(const_castreinterpret_caststatic_castdynamic_cast)

03-19

rn总结C++中的所有强制转换函数(const_cast,reinterpret_cast,static_cast,dynamic_cast)rnrnC 风格(C-style)强制转型如下:rnrn(T) expression // cast expression to be of type Trnrn函数风格(Function-style)强制转型使用这样的语法:rnrnT(expression) // cast expression to be of type Trnrn这两种形式之间没有本质上的不同,它纯粹就是一个把括号放在哪的问题。我把这两种形式称为旧风格(old-style)的强制转型。rnrn使用标准C++的类型转换符:static_cast、dynamic_cast、reinterpret_cast、和const_cast。rnrn3.1 static_castrn用法:static_cast < type-id > ( expression ) rn该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:rn①用于类层次结构中基类和子类之间指针或引用的转换。rn进行上行转换(把子类的指针或引用转换成基类表示)是安全的;rn进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。rn②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。rn③把空指针转换成目标类型的空指针。rn④把任何类型的表达式转换成void类型。rnrn注意:static_cast不能转换掉expression的const、volitale、或者__unaligned属性。rnrnrn3.2 dynamic_castrn用法:dynamic_cast < type-id > ( expression )rn该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;rn如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。rnrndynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。rn在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;rn在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。rnclass Brnpublic:rn int m_iNum;rn virtual void foo();rn;rnrnclass D:public Brn public:rn char *m_szName[100];rn;rnrnvoid func(B *pb)rn D *pd1 = static_cast(pb);rn D *pd2 = dynamic_cast(pb);rnrnrn在上面的代码段中,如果pb指向一个D类型的对象,pd1和pd2是一样的,并且对这两个指针执行D类型的任何操作都是安全的;rn但是,如果pb指向的是一个B类型的对象,那么pd1将是一个指向该对象的指针,对它进行D类型的操作将是不安全的(如访问m_szName),rn而pd2将是一个空指针。rnrn另外要注意:B要有虚函数,否则会编译出错;static_cast则没有这个限制。rn这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表(rn关于虚函数表的概念,详细可见)中,只有定义了虚函数的类才有虚函数表,rn没有定义虚函数的类是没有虚函数表的。rnrn另外,dynamic_cast还支持交叉转换(cross cast)。如下代码所示。rnclass Arnpublic:rn int m_iNum;rn virtual void f()rn;rnrnclass B:public Arn;rnrnclass D:public Arn;rnrnvoid foo()rn B *pb = new B;rn pb->m_iNum = 100;rnrn D *pd1 = static_cast(pb); //compile errorrn D *pd2 = dynamic_cast(pb); //pd2 is NULLrn delete pb;rnrnrn在函数foo中,使用static_cast进行转换是不被允许的,将在编译时出错;而使用 dynamic_cast的转换则是允许的,结果是空指针。rnrnrn3.3 reinpreter_castrn用法:reinpreter_cast (expression)rntype-id必须是一个指针、引用、算术类型、函数指针或者成员指针。rn它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,rn在把该整数转换成原类型的指针,还可以得到原先的指针值)。rnrn该运算符的用法比较多。rnrn3.4 const_castrn用法:const_cast (expression)rn该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。rn常量指针被转化成非常量指针,并且仍然指向原来的对象;rn常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。rnrnVoiatile和const类试。举如下一例:rnclass Brnpublic:rn int m_iNum;rnrnvoid foo()rnconst B b1;rnb1.m_iNum = 100; //comile errorrnB b2 = const_cast(b1);rnb2. m_iNum = 200; //finernrn上面的代码编译时会报错,因为b1是一个常量对象,不能对它进行改变;rn使用const_cast把它转换成一个常量对象,就可以对它的数据成员任意改变。注意:b1和b2是两个不同的对象。rnrn== ===========================================rnrn== dynamic_cast .vs. static_castrn== ===========================================rnrnclass B ... ;rnclass D : public B ... ;rnrnvoid f(B* pb)rnrnrnD* pd1 = dynamic_cast(pb);rnrnD* pd2 = static_cast(pb);rnrnrnIf pb really points to an object of type D, then pd1 and pd2 will get the same value. They will also get the same value if pb == 0.rnrnIf pb points to an object of type B and not to the complete D class, then dynamic_cast will know enough to return zero. However, static_cast relies on the programmer’s assertion that pb points to an object of type D and simply returns a pointer to that supposed D object.rnrn即dynamic_cast可用于继承体系中的向下转型,即将基类指针转换为派生类指针,比static_cast更严格更安全。dynamic_cast在执行效率上比static_cast要差一些,但static_cast在更宽上范围内可以完成映射,这种不加限制的映射伴随着不安全性。static_cast覆盖的变换类型除类层次的静态导航以外,还包括无映射变换、窄化变换(这种变换会导致对象切片,丢失信息)、用VOID*的强制变换、隐式类型变换等...rnrnrn== ===========================================rn== static_cast .vs. reinterpret_castrn== ================================================rnrnreinterpret_cast是为了映射到一个完全不同类型的意思,这个关键词在我们需要把类型映射回原有类型时用到它。我们映射到的类型仅仅是为了故弄玄虚和其他目的,这是所有映射中最危险的。(这句话是C++编程思想中的原话)rnrnstatic_cast 和 reinterpret_cast 操作符修改了操作数类型。它们不是互逆的; static_cast 在编译时使用类型信息执行转换,在转换执行必要的检测(诸如指针越界计算, 类型检查). 其操作数相对是安全的。另一方面;reinterpret_cast 仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换, 例子如下:rnrnint n=9; double d=static_cast < double > (n);rnrn上面的例子中, 我们将一个变量从 int 转换到 double。 这些类型的二进制表达式是不同的。 要将整数 9 转换到 双精度整数 9,static_cast 需要正确地为双精度整数 d 补足比特位。其结果为 9.0。而reinterpret_cast 的行为却不同:rnrnint n=9;rnrndouble d=reinterpret_cast (n);rnrn这次, 结果有所不同. 在进行计算以后, d 包含无用值. 这是因为 reinterpret_cast 仅仅是复制 n 的比特位到 d, 没有进行必要的分析.rnrn因此, 你需要谨慎使用 reinterpret_cast.rn#rn# 标准c++中主要有四种强制转换类型运算符: rn# rn# const_cast,reinterpret_cast,static_cast,dynamic_cast等等。 rn# rn# rn# rn# rn# 1)static_cast(a) rn# rn# 将地址a转换成类型T,T和a必须是指针、引用、算术类型或枚举类型。 rn# rn# 表达式static_cast(a), a的值转换为模板中指定的类型T。在运行时转换过程中,不进行类型检查来确保转换的安全性。 rn# rn# rn# rn# rn# 例子: rn# rn# rn# rn# rn# class B ... ; rn# rn# class D : public B ... ; rn# rn# void f(B* pb, D* pd) rn# rn# rn# rn# D* pd2 = static_cast(pb); // 不安全, pb可能只是B的指针 rn# rn# rn# rn# rn# B* pb2 = static_cast(pd); // 安全的 rn# rn# ... rn# rn# rn# rn#rnrn# 2)dynamic_cast(a) rn# rn# 完成类层次结构中的提升。T必须是一个指针、引用或无类型的指针。a必须是决定一个指针或引用的表达式。 rn# rn# 表达式dynamic_cast(a) 将a值转换为类型为T的对象指针。如果类型T不是a的某个基类型,该操作将返回一个空指针。 rn# rn# rn# rn# rn# 例子: rn# rn# class A ... ; rn# rn# class B ... ; rn# rn# void f() rn# rn# rn# rn# A* pa = new A; rn# rn# B* pb = new B; rn# rn# void* pv = dynamic_cast(pa); rn# rn# // pv 现在指向了一个类型为A的对象 rn# rn# ... rn# rn# pv = dynamic_cast(pb); rn# rn# // pv 现在指向了一个类型为B的对象 rn# rn# rn# rn# rn# rn# rn# 3)const_cast(a) rn# rn# 去掉类型中的常量,除了const或不稳定的变址数,T和a必须是相同的类型。 rn# rn# 表达式const_cast(a)被用于从一个类中去除以下这些属性:const, volatile, 和 __unaligned。 rn# rn# rn# rn# rn# 例子: rn# rn# rn# rn# rn# rn# rn# rn# class A ... ; rn# rn# void f() rn# rn# rn# rn# const A *pa = new A;//const对象 rn# rn# A *pb;//非const对象 rn# rn# rn# rn# rn# //pb = pa; // 这里将出错,不能将const对象指针赋值给非const对象 rn# rn# pb = const_cast(pa); // 现在OK了 rn# rn# ... rn# rn# rn#rnrn# 4)reinterpret_cast(a) rn# rn# 任何指针都可以转换成其它类型的指针,T必须是一个指针、引用、算术类型、指向函数的指针或指向一个类成员的指针。 rn# rn# 表达式reinterpret_cast(a)能够用于诸如char* 到 int*,或者One_class* 到 Unrelated_class*等类似这样的转换,因此可能是不安全的。 rn# rn# rn# rn# rn# 例子: rn# rn# class A ... ; rn# rn# class B ... ; rn# rn# void f() rn# rn# rn# rn# A* pa = new A; rn# rn# void* pv = reinterpret_cast(pa); rn# rn# // pv 现在指向了一个类型为B的对象,这可能是不安全的 rn# rn# ... rn# rn#

没有更多推荐了,返回首页