C++的类型转换运算符总结

C语言的类型转换比较自由,但也带来了一些问题,这些问题大多由程序员自行控制和解决。对于庞大的C++语言机制而言,这种简单粗暴的类型转换方式显然是个巨大的负担,因此C++引入4种类型转换运算符,更加严格的限制允许的类型转换,使转换过程更加规范:

dynamic_cast 用于多态类型的转换
static_cast 用于非多态类型的转换
const_cast 用于删除const ,volatile 和 __unaligned 属性
reinterpret_cast 用于位的简单重新解释
其中,const_cast和reinterpret_cast的使用会带来更大的风险,因此不到万不得已,不推荐使用。

dynamic_cast
dynamic_cast(expression);
作用: 将expression转换为type类型.

备注:
  1、转换类型必须是一个指针、引用或者void*,用于将基类的指针或引用安全地转换成派生类的指针或引用;
  2、dynamic_cast在运行期间强制转换,运行时进行类型转换检查;
  3、对指针进行转换,失败返回null,成功返回type类型的对象指针,对于引用的转换,失败抛出一个bad_cast ,成功返回type类型的引用;
  4、dynamic_cast不能用于内置类型的转换;
  5、用于类的转换,基类中一定要有virtual定义的虚函数(保证多态性),不然会编译错误。
   在这里插入图片描述
  没有多态性的基类无法进行dynamic_cast强制转换
举个例子:
dynamic_cast最常用的场景就是将原本“指向派生对象的基类指针或引用”升级为“派生类指针或引用”,比如——
#include
using namespace std;
// 基类
class Base {
public:
virtual void show() {
cout << “void Base::show();” << endl;
};
virtual ~Base() {};
};
//派生类
class Derived :public Base {
public:
void show() {
cout << “void Derived::show();” << endl;
};
};
int main() {
Basebase = new Derived;
if (Derived
derived = dynamic_cast<Derived*>(base)) {
cout << “基类指针转换派生类指针成功” << endl;
derived->show();
}
else {
cout << “基类指针转换派生类指针失败” << endl;
//derived->show();
}
base = new Base;
if (Derived* derived = dynamic_cast<Derived*>(base)) {
cout << “基类指针转换派生类指针成功” << endl;
derived->show();
}
else {
cout << “基类指针转换派生类指针失败” << endl;
//derived->show();
}

cin.get();
return 0;

}
在这里插入图片描述
static_cast
static_cast(expression);
#include
using namespace std;

class Another {};
class Base {};
class Derived :public Base {};

int main() {
// 通过编译,且是安全的
Basebase = static_cast<Base>(new Derived);
// 通过编译,但是存在安全隐患
Derivedd = static_cast<Derived>(new Base);
// 没有任何关系的两个类,无法转换,static_cast执行编译时类型检查
Anothera = static_cast<Base>(new Base);
return 0;
}

② 可以用于内置类型的转换。
  C语言与自己的内置类型隐式转换规则的,比如说,算术运算,低类型自动往高类型转换(如图),但转换的精度损失由开发者负责,编译器往往会提出警告。使用了static_cast运算符之后,等于告诉编译器,“我知道这里发生了类型转换,我会为转换的安全性负责,你不用管了”,编译器不会发出编译警告,除非你类型转换完全非法(比如 int a = static_cast(“Hello world!”); ),static_cast才会报编译错误;
 在这里插入图片描述
  ③ 把void*转换成目标类型的指针;
  ④ 把任意类型转换成void类型;
  ⑤ static_cast无法转换expression的const/volitale/__unaligned属性(会报编译时错误)
const_cast
const_cast(expression)
作用: 弥补了static_cast无法转换const/volitale的不足,将expression的const/volitale属性移除,仅限于底层const属性。
备注:
  ① 顶层const:表示指针变量是const的,比如int *const pointer;,底层const:表示指针所指向的变量是const的,比如const int *pointer;。理解记忆:所谓底层const就是指我这个变量“底子”就是const,改不了,天生丽质难自弃。反之,则是顶层const。
  ② const_cast不能执行其他任何类型转换,只能用于同类型之间不同const/volitale属性的移除。否则会报编译时错误。
  ③ 需要注意的是,const_cast通常对指针和引用进行转换,而无法直接移除内置类型的const/volitale属性,换言之,这种语法直接提供了一个具有写权限的指针或引用,可以通过间接访问的方式,修改常量。
举个例子
#include
using namespace std;

int main() {
const int a = 10;
const intpointer_const = &a;
int
b = const_cast<int*>(pointer_const);
*b = 20;
cout << "b = " << b << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "&a = " << &a << endl;
// a = 50; // 指向a的指针b可以修改a,但是a自身不能修改,因为a是常量
return 0;
}
在这里插入图片描述
  通过const_cast 常量a被修改。但是这里有个有趣的现象,就是,指向a的 指针b被修改了,但是a本身却还是没变,从地址上看,指针b确实指向了常量a,但是
b和a却不一样,这是为什么呢?
  推测可能是编译器(这里用的Visual Studio 2017)对字面型常量的引用,有自己的优化,所以a的值没有发生更改,但实际上已经改了,比如换种方式——

#include
using namespace std;

int main() {
cout<<“请输入一个数:”<<endl;
int input;
cin>>input;
const int a = input;
const intpointer_const = &a;
int
b = const_cast<int*>(pointer_const);
b = 20;
cout << "b = " << b << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "&a = " << &a << endl;
return 0;
}
在这里插入图片描述
这时会发现,常量a也能改变了(但仍然无法使用a = 30这样的赋值语句来改变a)。
reinterpret_cast
reinterpret_cast(expression);
作用: reinterpret_cast 允许将任何指针转换为任何其他指针类型。 也允许将任何整数类型转换为任何指针类型以及反向转换。
备注:
  ① reinterpret_cast 运算符可用于 char
到 int
或 One_class* 到 Unrelated_class* 之类的转换,这本身并不安全,但可以通过编译;
  ② reinterpret_cast 的本质作用是重新定义内存数据的解释方式,而不进行任何二进制转换。
举个例子:
char s[] = “hello world!”;
long l= reinterpret_cast(s);// 这里的作用是取字符串s的地址,地址转换成了long型;
cout << "l = " << l << endl;
在这里插入图片描述
总结
  C++提供了这四种类型强制转换符,主要作用是应对更高级的语法,以及更复杂的情况,以保证更好的安全性。毕竟C++的高级语法,还是蛮复杂的,如果类型转换像C语言一样自由而没有限制,必然会带来一连串问题。这种机制,一定程度上限定了类型转换的“规则”。
  但对于比较简单的类型转换,大可不必这么复杂,直接用强制转换(而不是强制转换运算符)即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值