C++的类型转换
- 一、C语言中的类型转换
- 二、C++的类型转换
- 1、static_cast
- 2、reinterpret_cast
- 3、const_cast
- 4、dynamic_cast
- 三、RTTI
一、C语言中的类型转换
在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换。
- 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败,注意:只有相近类型之间才能发生隐式类型转换
- 显式类型转化:需要用户自己处理
例如:比如int
和double
表示的都是数值,只不过它们表示的范围和精度不同。而指针类型表示的是地址编号,因此整型和指针类型之间不会进行隐式类型转换,如果需要转换则只能进行显式类型转换。
void Test()
{
int i = 1;
// 隐式类型转换
double d = i;
printf("%d, %.2f\n", i, d);
int* p = &i;
// 显示的强制类型转换
int address = (int)p;
printf("%x, %d\n", p, address);
}
C语言类型转换的优缺点::
C风格的转换格式很简单,但还是有不少缺点的:
- 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
- 显式类型转换将所有情况混合在一起,代码不够清晰
C语言转换的可视性比较差,相近类型之间发生隐式类型转换,难以跟踪错误的转换。
因此C++
为了加强类型转换的可视性,提出了自己的类型转化风格,因为C++
要兼容C
语言,所以C++
中还可以使用C
语言的转化风格。
二、C++的类型转换
标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符:static_cast
、reinterpret_cast
、const_cast
、dynamic_cast
1、static_cast
static_cast
用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast
,但它不能用于两个不相关的类型进行转换。
int main()
{
double d = 10.21;
int i = static_cast<int> (d);
cout << i << " " << d << endl;
// 转换失败
//int* p = static_cast<int*> (i);
//cout << p << endl;
return 0;
}
2、reinterpret_cast
reinterpret_cast
操作符通常为重新解释,用于将一种类型转换为另一种不同的类型。
int main()
{
// 转换失败
//double d = 10.21;
//int i = reinterpret_cast<int> (d);
//cout << i << " " << d << endl;
// 转换成功
int a = 10;
int* p = reinterpret_cast<int*> (a);
cout << p << endl;
return 0;
}
3、const_cast
const_cast
最常用的用途就是删除变量的const
属性,方便赋值,注意const_cast<>
<>里面必须是指针或者引用类型。
int main()
{
const int a = 10;
int* pa = const_cast<int*> (&a);
*pa = 20;
cout << " a :" << a << endl;
cout << "*pa :" << *pa << endl;
return 0;
}
可能看到这个结果你会很不解,明明我们都已经修改了a,为什么打印的结果还是10?
解释一下:
- 由于编译器认为
const
修饰的变量是不会被修改的,因此会将const
修饰的变量存放到寄存器当中,当需要读取const
变量时就会直接从寄存器中进行读取,而我们修改的实际上是内存中的a
的值,因此最终打印出a
的值是未修改之前的值。 - 如果不想让编译器将const变量优化到寄存器当中,可以用
volatile
关键字对const变量进行修饰,这时当要读取这个const变量时编译器就会从内存中进行读取,即保持了该变量在内存中的可见性。
int main()
{
volatile const int a = 10;
int* pa = const_cast<int*> (&a);
*pa = 20;
cout << " a :" << a << endl;
cout << "*pa :" << *pa << endl;
return 0;
}
4、dynamic_cast
dynamic_cast
用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
- 向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
- 向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)
而向下转型分为两种情况:
-
如果父类的指针(或引用)指向的是一个父类对象,那么将其转换为子类的指针(或引用)是不安全的,因为转换后可能会访问到子类的资源,而这个资源是父类对象所没有的。
-
如果父类的指针(或引用)指向的是一个子类对象,那么将其转换为子类的指针(或引用)则是安全的。
使用C风格的强制类型转换进行向下转型是不安全的,因为此时无论父类的指针(或引用)指向的是父类对象还是子类对象都会进行转换。
而使用dynamic_cast
进行向下转型则是安全的。
- 如果父类的指针(或引用)指向的是子类对象那么
dynamic_cast
会转换成功。 - 如果父类的指针(或引用)指向的是父类对象那么
dynamic_cast
会转换失败并返回一个空指针。
class A
{
public:
virtual void f()
{}
private:
int _a;
};
class B : public A
{
private:
int _b;
};
int main()
{
A aa;
B bb;
A* pa = &aa;
A* pb = &bb;
cout << "强制类型转换, 父转子pa:" << (B*)pa << endl;
cout << "强制类型转换, 父转子pb:" << (B*)pb << endl;
cout << "---------------------------------------" << endl;
cout << "dynamic_cast类型转换, 父转子pb:" << dynamic_cast<B*>(pa) << endl;
cout << "dynamic_cast类型转换, 父转子pb:" << dynamic_cast<B*>(pb) << endl;
}
注意:
-
dynamic_cas
t只能用于父类含有虚函数的类 -
dynamic_cast
会先检查是否能转换成功,能成功则转换,不能则返回0
三、RTTI
RTTI:Run-time Type identification的简称,即:运行时类型识别。
C++通过以下方式来支持RTTI:文章来源:https://uudwc.com/A/y5p1p
-
typeid
运算符 -
dynamic_cast
运算符 decltype
4中类型转化的应用场景:文章来源地址https://uudwc.com/A/y5p1p
-
static_cast
用于相近类型的类型之间的转换,编译器隐式执行的任何类型转换都可用static_cast
。 -
reinterpret_cast
用于两个不相关类型之间的转换。 -
const_cast
用于删除变量的const属性,方便赋值。 -
dynamic_cast
用于安全的将父类的指针(或引用)转换成子类的指针(或引用)。