本篇文章讲解C++的类型转换
C++中的类型转换分为隐式转换和显式转换
隐式转换是指编译器根据我们数据类型自动调整部分数据类型的转换过程,因为是编译器管理的,所以,我们必须知道编译器的转换规则。
根据数据类型的不同,隐式转换分为
要想弄清算术类型的转换规则,首先得知道编译器在进行算术类型转换的时候的原则:
整型会转换成浮点型
。int main(int argc, const char* argv[])
{
long long a = 1;
float b = 1.2;
std::cout << typeid(a + b).name() << std::endl;
return 0;
}
最后结果输出float。整型提升
。看下面代码:int main(int argc, const char* argv[])
{
bool a;
char b = 'c';
signed char f = 'f';
unsigned char c= 'd';
short d = 10;
unsigned short e = 10;
int g = 20;
std::cout << typeid(a + a).name() << std::endl;
std::cout << typeid(b + b).name() << std::endl;
std::cout << typeid(c + c).name() << std::endl;
std::cout << typeid(d + d).name() << std::endl;
std::cout << typeid(e + e).name() << std::endl;
std::cout << typeid(f + f).name() << std::endl;
std::cout << typeid(g + g).name() << std::endl;
}
输出结果全部都是int通常表示范围小的类型要转化成表示范围大的类型
,比如:
int main(int argc, const char* argv[])
{
int a = 1;
long b = 2;
long long c = 3;
std::cout << typeid(a + b).name() << std::endl;
std::cout << typeid(b + c).name() << std::endl;
std::cout << typeid(a + c).name() << std::endl;
}
输出结果为:long
__int64
__int64
带符号类型的运算对象转换成无符号类型
。看下面代码:int main(int argc, const char* argv[])
{
unsigned short a = 1;
unsigned int b = 1;
long c = 2;
std::cout << typeid(a + c).name() << std::endl;
std::cout << typeid(b + c).name() << std::endl;
}
结果为:long
// unsigned int和long都是四个字节,所以b无法转换成c,c由long转换成unsigned long
unsigned long
在大多数用到数组的表达式中,数组自动转换成指向数组首元素的指针
C++还规定几种其他的指针转换方式,包括
存在一种从算术类型或指针类型向布尔类型自动转换的机制。如果指针或算术类型的值为0,转换结果是false,否则转换结果是true
类类型能定义由编译器自动执行的转换,不过编译器每次只能执行一种类类型的转换
显式转换也叫强制类型转换,显式转换表示转换结果由程序员自己负责,所以要慎重。有四种强制转换方法:
任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast,这也是我们使用最多的类型转换,想象C语言中的显式转换方法,看下面代码:
long c = 2;
unsigned short a = (unsigned short)c;
这种是C语言的用法,我们可以使用static_cast实现相同的意思
long c = 2;
unsigned short a = static_cast<unsigned short>(c);
动态类型转换,编译器不进行转换检查
能将父类的指针或者引用安全地转换为子类的指针或者引用。
const_cast只能改变指针或者引用的底层const
一旦我们去掉了某个对象的const性质,编译器就不再阻止我们对该对象进行写操作了。 如果对象本身不是一个常量,使用强制类型转换获得写权限是合法的行为。 然而如果对象是一个常量,再使用const_cast 执行写操作就会产生未定义的后果,看下面的例子:
int main(int argc, const char* argv[])
{
const int a = 90;
const int* p = &a;
int* b = const_cast<int*>(p);
*b = 120;
std::cout << *b << std::endl;
std::cout << a << std::endl;
}
上面打印的结果是
120
90
也就是说对于const int a来说,虽然通过const_cast去掉了对应指针的底层const,但是a毕竟是一个常量。所以不要这样去改变a的值。
但是如果a不是一个常量,我们把
const int a = 90;
改成
int a = 90;
打印的结果是
120
120
总结一下:
const_cast应该用于那些本来不是常量,但是后来可能经过一系列操作,比如参数传递,变成了const类型,这种情况我们可以使用const_cast来去掉const的限制。
reinterpret_cast可以实现任意类型的转换,并且编译器不会给出任何警告或者错误提示。要谨慎使用转换后的值。