C++进阶(二)四种类型转换(static_cast, const_cast, dynamic_cast, reinterpret_cast)
在 C
语言中,如果要对类型进行转换,直接使用强制类型转换。这种转换使得表达式的精度有所损失,会出现一些未定义错误。这种强制转换方式有如下缺点:
- 任何类型都能进行强制转换,编译器很难判断其正确性
- 在源码中,无法定位所有强制类型转换的语句
(Type) (expression);
Type(expression);
C++中提出4种安全可靠的类型转换方式:static_cast
,const_cast
,dynamic_cast
,reinterpret_cast
。下面来分别介绍每种类型转换的应用场景及用法。
static_cast 类型转换
static_cast
是一种静态类型转换,用于基本类型转换,但不能用于基本类型指针之间的转换。也可用于继承关系的类对象的转换和类指针之间的转换。
示例1:基本类型之间的转换
#include <iostream>
using namespace std;
int main()
{
float f = 3.5;
int a = f; // C 中隐式类型转换
int b = static_cast<int>(f); // C++ 中强制类型转换
cout << b << endl;
}
编译执行,浮点型变量转换为 整型。
示例2:static_cast 不能用于指针之间的类型转换
#include <iostream>
using namespace std;
int main(){
int i = 0x123456;
char c = 'c';
int* pi = &i;
char* pc = &c;
c = static_cast<char>(i);
pc = static_cast<char*>(pi); // 无法在指针类型间进行转换
return 0;
}
编译出错,无法将 int*
转换为 char*
类型。
注释掉指针类型后,编译执行即可通过,下面再看下从int
类型强制转换为 char
类型,编译器如何转换。
示例3:类中定义类型转换函数(operator Type()
)
#include <iostream>
#include <string>
using namespace std;
class Int {
int x;
public:
Int(int x_in = 0)
: x{ x_in }
{
cout << "Conversion Ctor called" << endl;
}
// C++ 中类型转换函数
operator string()
{
cout << "Conversion Operator" << endl;
return to_string(x);
}
};
int main()
{
Int obj(3); // Int 对象,调用构造函数
// Int -> string 对象 ,相当于 string str = obj.string(obj)
string str = obj;
// 隐式类型转换,20 --> Int(20),调用构造函数
obj = 20;
// Int -> string 对象,相当于string str2 = obj.string(obj)
string str2 = static_cast<string>(obj);
// 显示强制类型转换, 30 --> Int(30),调用构造函数
obj = static_cast<Int>(30);
return 0;
}
编译运行,输出如下:
Conversion Ctor called
Conversion Operator
Conversion Ctor called
Conversion Operator
Conversion Ctor called
示例4:继承关系的类对象之间的转换,基类指针指向父类对象
#include <iostream>
using namespace std;
class Base {
};
class Derived : public Base { // 必须为public 继承,才能进行强制类型转换
};
int main()
{
Derived d1;
Base* b1 = (Base*)(&d1); // C语言中强制类型转换
Base* b2 = static_cast<Base*>(&d1); // C++ 中强制类型转换
return 0;
}
编译指向,可以看到使用 static_cast
类型转换符将基类指针指向子类对象。
const_cast 类型转换
const_cast
用于去除变量的只读属性,强制转换的目标类型是指针或引用。
示例一:在 const
成员函数中修改类中 non-const
成员变量。
#include <iostream>
using namespace std;
class student
{
private:
int roll;
public:
// constructor
student(int r):roll(r) {}
// A const function that changes roll with the help of const_cast
void fun() const
{
( const_cast <student*> (this) )->roll = 5;
}
int getRoll() { return roll; }
};
int main(void)
{
student s(3);
cout << "Old roll number: " << s.getRoll() << endl;
s.fun();
cout << "New roll number: " << s.getRoll() << endl;
return 0;
}
编译运行结果如下:
Old roll number: 3
New roll number: 5
在const
成员函数中,将this
指针修改为 const Student* const
,使用 const_cast
强制类型转换,使得const Student* const
修改为 Student* const
,所以可以修改 Student对象。
示例2:将常量指针强制转换为普通指针
int fun(int* ptr)
{
return (*ptr + 10);
}
int main(void)
{
const int val = 10;
const int *ptr = &val;
int *ptr1 = const_cast <int *>(ptr); // 转换为普通指针,作为参数传递
cout << fun(ptr1);
return 0;
}
示例3:const_cast
将指向const对象的指针进行强制类型转换,会产生未定义行为。
#include <iostream>
using namespace std;
int fun(int* ptr)
{
*ptr = *ptr + 10;
return (*ptr);
}
int main(void)
{
const int val = 10;
const int *ptr = &val; // const指针指向const变量
int *ptr1 = const_cast <int *>(ptr); // 未定义行为,将const指针的const属性去掉,会使得普通指针指向常量,此时通过指针修改常量,产生未定义行为
fun(ptr1);
cout << val;
return 0;
}
程序可以编译运行,但是会输出10
。因为在指向常量值,常量值无法改变。
示例4:const_cast
类型安全,无法在不同的类型之间进行转换
#include <iostream>
using namespace std;
int main(void)
{
int a1 = 40;
const int* b1 = &a1;
char* c1 = const_cast <char *> (b1); // 编译失败,无法将int * 转换为 char *
*c1 = 'A';
return 0;
}
示例5:const_cast
可以将 volatile
类型转化为非 volatitle
类型
#include <iostream>
#include <typeinfo>
using namespace std;
int main(void)
{
int a1 = 40;
const volatile int* b1 = &a1;
cout << "typeid of b1 " << typeid(b1).name() << '\n';
int* c1 = const_cast <int *> (b1);
cout << "typeid of c1 " << typeid(c1).name() << '\n';
return 0;
}
编译输出
typeid of b1 PVKi // Pointer to a volatile and constant integer
typeid of c1 Pi // Pointer to integer
reinterpret_cast 类型转换
reinterpret_cast
用于指针类型之间的类型转换,也用于整数与指针之间的类型转换。用法如下
data_type *var_name =
reinterpret_cast <data_type *>(pointer_variable);
示例1:指针类型转换(将int*
强制转换为 char*
)
// CPP program to demonstrate working of
// reinterpret_cast
#include <iostream>
using namespace std;
int main()
{
int* p = new int(65);
char* ch = reinterpret_cast<char*>(p);
cout << *p << endl;
cout << *ch << endl;
cout << p << endl;
cout << ch << endl;
return 0;
}
编译输出,将int*
转换为 char*
,输出字符A
65 // 原始数值
A // 将int* 转换为 char*,65 --> A
0xf31c90 // 输出地址
A // 输出字符
示例2:类之间的强制类型转换
// CPP code to illustrate the pointer reinterpret
#include <iostream>
using namespace std;
class A {
public:
void fun_a()
{
cout << " In class A\n";
}
};
class B {
public:
void fun_b()
{
cout << " In class B\n";
}
};
int main()
{
// creating object of class B
B* x = new B();
// converting the pointer to object
// referenced of class B to class A
A* new_a = reinterpret_cast<A*>(x);
// accessing the function of class A
new_a->fun_a();
return 0;
}
编译输出,得到
In class A
dynamic_cast 类型转换
dynamic_cast
只能虚函数的类使用,用于具有继承关系的类之间的类型转换;也用于有交叉关系的类指针的类型转换。dynamic_cast
可以进行类型检查。
巨人的肩膀
一键三连是对我的最大支持与鼓励。欢迎关注编程小镇,每天涨一点新姿势😄。