命名的强制类型转换符号的一般形式如下:
cast_name<type>(expression);
其中, cast_name可以为dynamic_cast、static_cast、const_cast和reinterpret_cast的一种,type为转换的目标类型,而expression则是被强制转换的值。下面分别讲一下他们的具体含义。
1、const_cast
设定或去除型别的常数性,亦可去除volatile饰词,除此之外不允许任何转换:
(1)常量指针被转化成非常量指针,并且仍然指向原来的对象;
(2)常量引用被转换成非常量引用,并且仍然指向原来的对象;
(3)常量对象被转换成非常量对象。
- #include<iostream>
-
- using namespace std;
-
- int main()
- {
- int num = 10;
- const int* ptr = #
- //int* ptr1 = ptr; //A
- int *ptr1 = const_cast<int*>(ptr)
- *ptr1 = 15;
- cout<<*ptr<<endl;;
- return 0;
- }
A行的赋值将会产生编译错误,不能将const int*转换为int*
2、static_cast
(1)static_cast用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。static_cast只能提供编译时的安全。进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。(如果原先基类指针指向的是基类,那么这么做就会出错);但是static_cast不能不在兄弟之间进行转换。
(2)用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
(3)把空指针转换成目标类型的空指针;把任何类型的表达式转换成void类型。
范例1:
- //class Der:public class Base
-
- //当pb确实指向一个Der,则这是使用两种转换方式都没问题
- Base *pb = new Der();
- Der *pd1 =static_cast<Der*>(pb);
- Der *pd2 =dynamic_cast<Der *>(pb);
-
- //当pb指向一个Base,则就有问题
- Base *pb = newBase();
- Der *pd1 =static_cast<Der*>(pb); //(1)
- Der *pd2 =dynamic_cast<Der *>(pb);//(2)
- //(1)此时pd1将是一个指向该对象的指针,对它进行D类型的操作将是不安全的。
- //(2)pd2将是一个空指针,即NULL指针。
范例2:
- //class Der:public class Base
- //class Der1:public class Base
-
- //static是无法在兄弟类之间完成转换的
- er *pb = new Der();
- Der1 *pd1 = static_cast<Der1 *>(pb);//编译错误
-
- Der1 *pd2 = reinterpret_cast<Der1 *>(pd);//可以完成
-
- Der1 *pd3 = dynamic_cast<Der1 *>(pd);//可以完成
-
- //pd2和pd3并不是真正转到相应的类型了
范例3:
- #include<iostream>
- #include<cstdio>
- using namespace std;
-
- class CBaseX{
- public:
- int x;
- CBaseX() { x = 10; }
- void foo() { printf("CBaseX::foo()x=%d\n", x); }
- };
-
- class CBaseY{
- public:
- int y;
- int* py;
- CBaseY() { y = 20; py = &y; }
- void bar() { printf("CBaseY::bar()y=%d, *py=%d\n", y, *py);}
- };
-
- class CDerived :public CBaseX, public CBaseY{
- public:
- int z;
- };
-
- int main()
- {
- CDerived *pd = new CDerived(); //1
- printf("CDerived* pd = %x\n",(int)pd);
-
- CBaseY *pb = pd; //2
- printf("CBaseX* pb = %x\n",(int)pb);
-
- CDerived* pd1 =static_cast<CDerived*>(pb); //3
- printf("CDerived* pd1 = %x\n",(int)pd1);
-
- CBaseY* pb2 =reinterpret_cast<CBaseY*>(pd); //4
- printf("CBaseY* pb2 = %x\n",(int)pb2);
-
- CBaseY* pb3 = new CBaseY(); //5
- printf("CBaseY* pb3 = %x\n",(int)pb3);
-
- CDerived* pd3 =static_cast<CDerived*>(pb3); //6
- printf("CDerived* pd3 = %x\n",(int)pd3);
-
- CDerived* pd4 =reinterpret_cast<CDerived*>(pb3); //7
- printf("CDerived* pd4 = %x\n", (int)pd4);
- return 0;
- }
运行结果:
针对上面的结果有如下分析:
//1:声明了一个指向派生类的指针
//2:一个简单的赋值,此时注意pb指向基类的指针,如果将派生类的指针赋给给它,此时pb只指向了派生类中基类对象的部分。
//3:此时将指向基类的指针转换为指向派生类的指针,注意它将pb的指针想前面移了4个位置,表示指向派生类。
//4:和第三行有同样的结果
//5:定义了一个指向基类的指针。
//6:这时还用static_cast转换,将指针往前面挪4个位置,但是由于本身就不存在派生类对象,这样访问前面的地址空间是不安全的。
//7:未做修改还是指向了原来的空间。
3、reinterpret_cast
C++中的reinterpret_cast主要是将数据从一种类型的转换为另一种类型。所谓“通常为操作数的位模式提供较低层的重新解释”也就是说将数据以二进制存在形式的重新解释。比如:
int i;
char *p = "This is aexample.";
i = reinterpret_cast<int>(p);
此时结果,i与p的值是完全相同的。reinterpret_cast的作用是说将指针p的值以二进制(位模式)的方式被解释为整型,并赋给i,//i 也是指针,整型指针;一个明显的现象是在转换前后没有数位损失。
范例:
- int n = 9;
- double d = reinterpert_cast<dboule&>(n);
- cout<<n<<" "<<d;
- //输出:9 5.28421e-308
- //因为reinterpert_cast仅仅是复制n的比特位到d,没有进行必要的分析。
4、dynamic_cast
如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。
如果是指针转换失败将返回NULL,如果是引用转换失败将抛出bad_cast.
dynamic_cast运算符可以在执行期决定真正的类型。如果downcast是安全的(也就说,如果基类指针或者引用确实指向一个派生类对象)这个运算符会传回适当转型过的指针。如果downcast不安全,这个运算符会传回空指针(也就是说,基类指针或者引用没有指向一个派生类对象)。
dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
注:static_cast要有虚函数,否则会编译出错;static_cast则没有这个限制。
注:dynamic_cast不支持反向转换。
范例1:
- #include<iostream>
-
- using namespace std;
-
- class A{
- public:
- int m_nA;
- };
-
- class B{
- public:
- int m_nB;
- };
-
- class C:public A,public B{
- public:
- int m_nC;
- };
-
- int main()
- {
- C *pC = new C;
- cout<<"pC= "<<(int) pC<<endl;
- B *pB = dynamic_cast<B*>(pC); //a
- B *pB1 = static_cast<B*>(pC); //b
- B *pB2 = pC; //c
- cout<<"pB= "<<(int) pB<<endl;
- cout<<"pB1="<<(int) pB1<<endl;
- cout<<"pB2="<<(int) pB2<<endl;
- return 0;
- }<span style="font-size:18px;">
- </span>
运行结果:
分析:这是一个派生类指针向基类指针转换的例子,这种转换只是将派生类指针向下挪几个位置(挪多少与具体成员有关),即指向到基类位置的地方。因为在派生类中既包含基类成员又包含派生类成员。
范例2:
- //一个常用的用法
- void fun(Base* pB)
- {
- Der* pd = dynamic_cast<Der*>(pb);
- if(pd){......}
- }
范例3:
- #include <iostream>
- using namespace std;
-
- class Base
- {
- public:
- virtual void f() { cout << "Base::f" << endl; }
- void f1(){cout << "Base::f1" << endl;}
- private:
- double x;
- double y;
- };
- class Derived : public Base
- {
- public:
- virtual void f(){cout << "Derived::f" << endl; }
- virtual void k(){cout << "Derived::k" << endl; }
- private:
- double z;
- };
- class Base1
- {
- public:
- virtual void g(){ cout << "Base1::g" << endl;}
- void g1(){cout << "Base1::g1" << endl;}
- };
- class Derived1 : public Base,public Base1
- {
- public:
- virtual void f(){ cout << "Derived1::f" << endl;}
- virtual void h(){ cout << "Derived1::h" << endl;}
- };
- void Test1()
- {
- // 对于单继承,
- // 如果pD真的指向Derived,用dynamic_cast和static_cast效果相同
- Base *pD = new Derived;
- Derived *pD1 = dynamic_cast<Derived*>(pD);
- pD1->f();
- pD1->k();
- pD1->f1();
- Derived *pD2 = static_cast<Derived*>(pD);
- pD2->f();
- pD2->k();
- pD2->f1();
- // 但是如果pB不是真的指向Derived,则用dynamic_cast则返回NULL,能够更早的禁止error的发生,
- // 如果用static_cast虽然返回的不为NULL,但是运行时可能抛出exception。
- /**///// Error code
- //Base *pB = new Base();
- //Derived *pD3 = static_cast<Derived*>(pB);
- //pD3->f();
- //pD3->k();
- //pD3->f1();
- //Derived *pD4 = dynamic_cast<Derived*>(pB);
- //pD4->f();
- //pD4->k();
- //pD4->f1();
- }
- void Test2()
- {
- // 对于多重继承,
- // 如果pD真的指向的是Derived1,使用dynamic_cast和static_cast都可以转化为Derived1,
- // 但是如果要转化为Base的兄弟类Base1,必须使用dynamic_cast,使用static_cast不能编译。
- Base *pD = new Derived1;
- Derived1 *pD1 = dynamic_cast<Derived1*>(pD);
- pD1->f();
- pD1->h();
- pD1->f1();
- Base1 *pB1 = dynamic_cast<Base1*>(pD);
- pB1->g();
- Derived1 *pD2 = static_cast<Derived1*>(pD);
- pD2->f();
- pD1->h();
- pD2->f1();
- /**///// error can not compiler
- //Base1 *pB2 = static_cast<Base1*>(pD);
- //pB2->g();
- // 当然对于pB不是真的指向Derived1,想要转化为Derived1或Base的兄弟类Base1,情况与Test1中的error情况相同。
- }
- int main(int argc, _TCHAR* argv[])
- {
- Test1();
- Test2();
- return 0;
- }<span style="font-size:18px;">
- </span>