在这里,我们将详细解释C++类型转换的情况。
1、隐式类型转换
在下列四种情形时会发生隐式类型转换
a)在混合表达式中,操作数会被转化为相同的类型
如a>b a+b等
b)在条件表达式中,操作数会被转化为bool类型
if(a)
c)在初始化和赋值中,也会发生类型转换
int a = 3.2
int p;p=0(0在这里被转换为了一个int类型的NULL指针)
d)在函数调用时
转换的原则如下:
在操作符两侧的遵循如下规则进行修改
double ←── float 高
↑
long
↑
unsigned
↑
int ←── char,short 低
2、显示类型转换
reinterpret_cast
只是将指针类型进行转换。也就是只在编译时从新解释指针的类型。不能用于非指针比如说一个的变换。tyid可以使指针,也可以是引用或者算数类型。
也就是说,指针指向位置的值没有变,只是重新解释了一下比特模型
也就是说,下面这种转换是没有意义的
int *n= new int ;
double *d=reinterpret_cast<double*> (n);
const_cast
用于去除指针变量的常属性,将它转换为一个对应指针类型的普通变量,反过来也可以将一个非常量指针转换为一个常量指针变量。实际上也可以用来移除volatile的关键字。
如果你用const声明了一个变量。现在无论如何向改变它。咋办?
直接改一定会编译报错的
const int constant = 21;
int* modifier = &constant
编译报错,无法从const int*转换为int*.这是因为const的变量取地址后会自动变成常量指针。(注意,C语言中上述办法是行的通的)
const int constant = 21;
int& modifier = constant;
上面的办法也不行,指针不行,引用自然也不行。
实际上可以使用下面的办法
const int constant = 21;
int* modifier = const_cast<int*>(&constant);
这是因为在C++中,指针之间的转换时任意的,不会检查类型。
实际上,不用const_cast<>,而直接使用(int*)强制类型转换也可以。
但是事情并没有这么简单,可以运行如下代码
int main()
{
const int constant = 21;
int* modifier = const_cast<int*>(&constant);
*modifier = 22;
std::cout << modifier << std::endl;
std::cout << &constant << std::endl;
std::cout << constant << std::endl;
std::cout << *modifier << std::endl;
return 0;
}
可以发现,打印出来的地址是一样的,值却是不同的。
事实上,这是C++标准中的未定义问题。留给编译器自己决定如何处理这个问题。为了避免这种情况出现,我们需要保证上述编码永远不会出现。即绝不对const数据进行重新赋值。
但是,既然我们不打算重新复制,我们在干什么呢?这是为了我们方便调用某些的只接受非const类型参数的函数。但是我们必须确保这些函数中不会对这些值进行更改。
void FuncChangeA(int* pa)
{
//虽说可以改变,但是编码风格不允许改变pa所指向的值。
}
int main()
{
const int constant = 21;
int* modifier = const_cast<int*>(&constant);
//*modifier = 22;//这种代码永远不该出现
//FuncChangeA(&constant);//编译器报错
FuncChangeA(modifier);
std::cout << modifier << std::endl;
std::cout << &constant << std::endl;
std::cout << constant << std::endl;
std::cout << *modifier << std::endl;
return 0;
}
static_cast
首先,所用隐式类型转换都是由static_cast完成的。
int main()
{
int i1;
int i2;
float f = 166.71;
i1 = static_cast<int>(f);
i2 = f;
std::cout << i1 << std::endl;//输出166
std::cout << i2 << std::endl;//输出166
return 0;
}
除此之外,也可以用于基本类型的数据转换。
char c = 'a';
int i3 = (int)c;
int i4 = static_cast<int>(c);
int i5 = c;
std::cout << i3 << std::endl;
std::cout << i4 << std::endl;
std::cout << i5 << std::endl;
最常用的办法,是进行基类和子类之间的类型转换.在这里,向上转型是安全的,和java一样。由于没有动态类型识别机制,向下转型是不安全的、这点也和java相同。
可以用于将空指针转化为目标类型的空指针
可以用于将任何类型的表达式转化为void类型。注意void是一种类型。
这里的术语很乱。空指针实际上指的是值为NULL(C++里就是0)的指针,本身可以有自己的类型。void类型的指针是指向void类型的,不管其值是什么。void类型的指针可以存储任何类型的指针。
dynamic_cast
只能在继承类对象的指针之间或引用之间进行类型转换
是一种运行时的转化,而上述其他都是编译时进行的。所以,依赖于RTTI信息。在转换时,会检查对象是否真的可以转换。这点是通过vtable实现的。这点,可以让我实现安全的向下转型。
其实显示类型转换还有一种,也就是我们最常用的一种,C风格的类型转换。也就是C语言中的强制类型转换。