本文主要是介绍C++四种强制类型转换:static_cast、const_cast、reinterpret_cast和dynamic_cast,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
C风格的强制转换
在C++基本的数据类型中,可以分为四类:整型,浮点型,字符型,布尔型。其中数值型包括 整型与浮点型;字符型即为char。
(1)将浮点型数据赋值给整型变量时,舍弃其小数部分。
(2)将整型数据赋值给浮点型变量时,数值不变,整型提升。
(3)将double型数据赋值给float型变量时,注意数值范围溢出。
(4)字符型数据可以赋值给整型变量,此时存入的是字符的ASCII码。
(5)将一个int,short或long型数据赋值给一个char型变量,只将低8位原封不动的送到char型变量中。
(6)将有符号型数据赋值给长度相同的无符号型变量,连同原来的符号位一起传送。
C++强制类型转换
在C++语言中新增了四个关键字static_cast、const_cast、reinterpret_cast和dynamic_cast。这四个关键字都是用于强制类型转换的。新类型的强制转换可以提供更好的控制强制转换过程,允许控制各种不同种类的强制转换。
C++中风格是static_cast(content)。C++风格的强制转换其他的好处是,它们能更清晰的表明它们要干什么。程序员只要扫一眼这样的代码,就能立即知道一个强制转换的目的。
1.static_cast:相干类型之间的转换
在C++语言中static_cast用于数据类型的强制转换,强制将一种数据类型转换为另一种数据类型。例如将整型数据转换为浮点型数据。
[例]C语言所采用的类型转换方式:
int a = 10;
int b = 3;
double result = (double)a / (double)b;
将整型变量a和b转换为双精度浮点型,然后相除。在C++语言中,我们可以采用static_cast关键字来进行强制类型转换,如下所示。
int a = 10;
int b = 3;
double result = static_cast<double>(a) / static_cast<double>(b);
2.const_cast:强制去掉这种不能被修改的常属性,但需要特别注意的是const_cast不是用于去除变量的常量性,而是去除指向常数对象的指针或引用的常量性,其去除常量性的对象必须为指针或引用。
[例]一个错误的例子:
const int a = 10;
const int * p = &a;
*p = 20; //compile error
int b = const_cast<int>(a); //compile error
在本例中出现了两个编译错误,第一个编译错误是*p因为具有常量性,其值是不能被修改的;另一处错误是const_cast强制转换对象必须为指针或引用,而例3中为一个变量,这是不允许的!
#include<iostream>
using namespace std;int main()
{const int a = 10;const int * p = &a;int *q;q = const_cast<int *>(p);*q = 20; //finecout <<a<<" "<<*p<<" "<<*q<<endl;cout <<&a<<" "<<p<<" "<<q<<endl;return 0;
}
在本例中,我们将变量a声明为常量变量,同时声明了一个const指针指向该变量(此时如果声明一个普通指针指向该常量变量的话是不允许的,Visual Studio 2010编译器会报错)。之后我们定义了一个普通的指针*q。将p指针通过const_cast去掉其常量性,并赋给q指针。之后我再修改q指针所指地址的值时,这是不会有问题的。
最后将结果打印出来,运行结果如下:
10 20 20
002CFAF4 002CFAF4 002CFAF4
3.reinterpret_cast:不相干类型的转换
reinterpret_cast主要有三种强制转换用途:改变指针或引用的类型、将指针或引用转换为一个足够长度的整形、将整型转换为指针或引用类型。
[例].将整型指针通过reinterpret_cast强制转换成了双精度浮点型指针。
//将整型指针通过reinterpret_cast强制转换成了双精度浮点型指针。
int *a = new int;
double *d = reinterpret_cast<double *>(a);
4. dynamic_cast:它要求所转换的操作数必须包含多态类类型(即至少包含一个虚函数的类);<>内部所描述的目标类型必须为指针或引用。
这里提出一个概念RTTI(运行时类型信息):通过运行时类型信息程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型。
(1)其他三种都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查。
(2)不能用于内置的基本数据类型的强制转换。
(3)dynamic_cast转换如果成功的话返回的是指向类的指针或引用,转换失败的话则会返回NULL。
(4)使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过。 Base类中需要检测有虚函数的原因:类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义。
(5)在类的转换时,在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
向上转换,即为子类指针指向父类指针(一般不会出问题);向下转换,即将父类指针转化子类指针。向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。
在C++中,编译期的类型转换有可能会在运行时出现错误,特别是涉及到类对象的指针或引用操作时,更容易产生错误。Dynamic_cast操作符则可以在运行期对可能产生问题的类型转换进行测试。
[例]一个错误的例子
#include<iostream>
using namespace std;class base
{
public :void m(){cout<<"m"<<endl;}
};class derived : public base
{
public:void f(){cout<<"f"<<endl;}
};int main()
{derived * p;p = new base;p = dynamic_cast<derived *>(new base);p->m();p->f();return 0;
}
在本例中利用dynamic_cast进行强制类型转换,但是因为base类中并不存在虚函数,因此p = dynamic_cast<derived *>(new base);这一句会编译错误。
为了解决本例中的语法错误,我们可以将base类中的函数m声明为虚函数,virtual void m(){cout<<“m”<<endl;}。
[例]正确示范
#include<iostream>
#include<cstring>using namespace std;class A
{public:virtual void f(){cout<<"hello"<<endl;};
};class B:public A
{public:void f(){cout<<"hello2"<<endl;};};class C
{void pp(){return;}
};int fun()
{return 1;
}int main()
{A* a1=new B;//a1是A类型的指针指向一个B类型的对象A* a2=new A;//a2是A类型的指针指向一个A类型的对象B* b;C* c;//结果为not null,向下转换成功,a1之前指向的就是B类型的对象,// 所以可以转换成B类型的指针。b=dynamic_cast<B*>(a1);if(b==NULL){cout<<"null"<<endl;}else{cout<<"not null"<<endl;}b=dynamic_cast<B*>(a2);//结果为null,向下转换失败if(b==NULL){cout<<"null"<<endl;}else{cout<<"not null"<<endl;}c=dynamic_cast<C*>(a);//结果为null,向下转换失败if(c==NULL){cout<<"null"<<endl;}else{cout<<"not null"<<endl;}delete(a);return 0;
}
这篇关于C++四种强制类型转换:static_cast、const_cast、reinterpret_cast和dynamic_cast的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!