大家好,我是酒馆店小二。
C风格的强制转换(Type Cast)容易理解,不管什么类型的转换都可以使用使用下面的方式。
TypeName res = (NewTypeName)ans;
当然,C++也是支持C风格的强制转换,但是C风格的强制转换可能带来一些隐患,让一些问题难以察觉。所以C++提供了一组可以用在不同场合的强制转换的函数。
const_cast用于强制去掉不能被修改的常数特性,其去除常量性的对象一般为指针或引用。
用法:const_cast
该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, new_type和expression的类型是一样的。
常量指针被转化成非常量指针,并且仍然指向原来的对象;
常量引用被转换成非常量引用,并且仍然指向原来的对象。
#include
#include
#include
#include
/*
* Author: 酒馆店小二
* Description: c++强制转换
* Date: 2022-03-10 17:14:56 星期四
* FileName: Trans.cpp
* Location: D:\VSCODE_CPP\mainshi\Trans.cpp
*/
using namespace std;
int main(int argc, char* argv[]){
int arr[4] = {1, 2, 3, 4}; // 原始数组
const int *c_ptr = arr; // 常量化数组指针
// c_ptr[1] = 233; // error,不能通过指针的形式改变数组的值
int *ptr = const_cast<int*>(c_ptr); // 通过const_cast 去常量
for (int i = 0; i < 4; i++) // 修改数据
ptr[i] += 10; //pass
for (int i = 0; i < 4; i++) // 打印修改后的数据
cout << arr[i] << " ";
cout << endl;
return 0;
}
static_cast静态转换相当于C语言中的强制转换,但不能实现普通指针数据(空指针除外)的强制转换,一般用于父类和子类指针、引用间的相互转换。没有运行时类型检查来保证转换的安全性。
①用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。不管是否发生多态,父子之间互转时,编译器都不会报错。
进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的,但是编译器不会报错。
②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
③把空指针转换成目标类型的空指针。
④把任何指针类型转换成空指针类型。
⑤可以对普通数据的const和non_const进行转换,但不能对普通数据取地址后的指针进行const添加和消去。
⑥无继承关系的自定义类型,不可转换,不支持类间交叉转换。
另外,static_cast不能转换掉原有类型的const、volatile、或者 __unaligned属性。(前两种可以使用const_cast 来去除)。
#include
#include
#include
#include
/*
* Author: 酒馆店小二
* Description: c++强制转换
* Date: 2022-03-10 17:14:56 星期四
* FileName: Trans.cpp
* Location: D:\VSCODE_CPP\mainshi\Trans.cpp
*/
using namespace std;
class Person {
};
class Son :public Person {
};
class My {};
void test02() {
char a = 'c';
int b = static_cast<int>(a);
cout << b << endl; // 99
const char a0 = 'c';
char b0 = static_cast<char>(a0);
cout << b0 << endl; // c
// 父类指针转为子类,下行,编译通过,不安全
Person *p = nullptr;
Son *s = static_cast<Son *>(p);
// 子类指针转为父类,上行,编译通过,安全
Son *s0 = nullptr;
Person *p0 = static_cast<Person *>(s0);
// My* my= static_cast(p); 无继承关系的自定义数据类型不能相互转换
//父类对象无法转为子类对象
// Person p1;
// Son s1 = static_cast(p1);
// 子类对象可以赋值,初始化父类对象
Son s2;
Person p2 = static_cast<Person>(s2);
// 父类引用转为子类,下行,编译通过,不安全
Person p_;
Person &p3 = p_;
Son &s3 = static_cast<Son &>(p3);
// 子类引用转为父类,上行,编译通过,安全
Son s_;
Son &s4 = s_;
Person &p4 = static_cast<Person &>(s4);
// 空指针转化为目标类型的指针
void *pPtr = nullptr;
int *iPtr = static_cast<int *>(pPtr);
// 任何指针转化为空指针类型
int *aInt = nullptr;
void *aVoid = static_cast<void *>(aInt);
// static_cast不能进行除void外的指针强制互转
char *tmp = "abc";
cout << tmp << endl; // abc
// cout << static_cast(tmp) << endl; // 不能将char*型的数据转换为int*,但C语言强转可以
int *tmpInt = 0;
cout << tmpInt << endl; // 0
cout << static_cast<void *>(tmpInt) << endl; // 0
cout << static_cast<int *>(tmpInt) << endl; // 转为自身可以, 0
}
int main(int argc, char* argv[]){
int arr[4] = {1, 2, 3, 4}; // 原始数组
const int *c_ptr = arr; // 常量化数组指针
// c_ptr[1] = 233; // error,不能通过指针的形式改变数组的值
int *ptr = const_cast<int*>(c_ptr); // 通过const_cast 去常量
for (int i = 0; i < 4; i++) // 修改数据
ptr[i] += 10; //pass
for (int i = 0; i < 4; i++) // 打印修改后的数据
cout << arr[i] << " ";
cout << endl;
int a = 10;
int b = 4;
double result = static_cast<double>(a) / static_cast<double>(b);
cout << result << endl; // 2.5
double d = 7;
void *p = &d;
double *dp = static_cast<double*>(p);
cout << *dp << endl; // 7
test02();
return 0;
}
动态转换的类型和操作数必须是完整类类型或空指针、空引用,说人话就是说,只能用于类间转换,支持类间交叉转换,不能操作普通数据。
主要用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换,
①进行上行转换(把派生类的指针或引用转换成基类表示)是安全的,允许转换;
②进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的,不允许转化,编译器会报错;
③发生多态时,允许互相转换。
④无继承关系的类之间也可以相互转换,类之间的交叉转换。
⑤如果dynamic_cast语句的转换目标是指针类型并且失败了,则结果为0。如果转换目标是引用类型并且失败了,则dynamic_cast运算符将抛出一个std::bad_cast异常
#include
#include
#include
#include
/*
* Author: 酒馆店小二
* Description: dynaimc_cast
* Date: 2022-03-10 18:16:24 星期四
* FileName: dynamic_trans.cpp
* Location: D:\VSCODE_CPP\mainshi\dynamic_trans.cpp
*/
using namespace std;
class Base{
public:
Base() {}
~Base() {}
void print() {
std::cout << "I'm Base" << endl;
}
virtual void i_am_virtual_foo() {}
};
class Sub: public Base{
public:
Sub() {}
~Sub() {}
void print() {
std::cout << "I'm Sub" << endl;
}
virtual void i_am_virtual_foo() {}
};
int main(int argc, char* argv[]) {
Base base;
Sub sub;
cout << "Sub->Base" << endl;
sub.print();
Sub* ps = ⊂
Base *pb = dynamic_cast<Base*>(ps);
if (pb != nullptr) { // 上行指针转换成功
pb->print();
} else {
cout << "base> pb val is: " << pb << endl;
}
cout << endl << "Base->Sub" << endl;
base.print();
Base *pb02 = &base;
Sub *ps02 = dynamic_cast<Sub*>(pb02);
if (ps02 != nullptr) { // 下行指针转换失败
ps02->print();
} else {
cout <<"sub> ps02 val is: " << ps02 << endl;
}
Base &refer = base;
try
{
Sub &d = dynamic_cast<Sub &>(refer);
d.print();
}
catch (const bad_cast &ex)
{
//下行引用转换失败,抛出std::bad_cast异常
cout << ex.what();
}
return 0;
}
在C++语言中,reinterpret_cast主要有几种强制转换用途:将指针或引用转换为一个足够长度的整型、将整型转换为指针或引用类型。
#include
#include
/*
* Author: 酒馆店小二
* Description: reinterpret_cast
* Date: 2022-03-10 18:53:17 星期四
* FileName: reinterpert_cast.cpp
* Location: D:\VSCODE_CPP\mainshi\reinterpert_cast.cpp
*/
using namespace std;
int main(int argc, char* argv[]) {
int *ptr = new int(233);
uint64_t ptr_addr = reinterpret_cast<uint64_t>(ptr);
cout << "ptr's address: " << hex << ptr << endl
<< "ptr_addr's address: " << hex << ptr_addr << endl;
delete ptr;
return 0;
}