目录
一.C语言类型转换
1.自动类型转换
C/C++中均提供自动类型转化,适用于部分内置类型的互相转换,语法格式如下:
目标类型 b = a;
如double c = 10.2;float d = c;发生自动类型转换,但由于double数据类型为64位,float为32位,故在转换时可能丢失数据精度,编译器会发出警告.若是不可自动类型转换的数据类型,编译器则会报错,此时需要用到强制类型转换.
2.强制类型转换
格式如下:
目标类型 b = (目标类型) a;
不管什么类型都可以直接进行转换,C++也是支持C语言的强制类型转换,但是C风格的强制类型转换可能会带来一些隐患,出现一些难以察觉的问题.
诶,这时候就有人会问了:兄弟兄弟,这个C语言类型强制转换还是太难操作了,到时候报错很难发现是类型转换出问题了怎么办?(简单,只需在编程时将其一把抓住,顷刻炼化,让它不出错就...)那有没有更加严谨,清晰的强制类型转化方法呢?
有的兄弟,有的,在C++中,新增了四个关键字static_cast、const_cast、reinterpret_cast和dynamic_cast,用于支持C++风格的强制类型转换来替代C风格的强制类型转换,降低使用风险.C++风格的强制类型转换能更清晰的表明它们要干什么,程序员只要看一眼这样的代码,立即能知道强制转换的目的,并且,在多态场景也只能使用C++风格的强制类型转换.C++风格的强制类型转换在多线程及网络编程中经常被用到.
注:C++的类型转换只是语法上的解释,本质上与C风格的类型转换没什么不同,C语言做不到事情的C++也做不到.
二.C++强制类型转换
语法:
static_cast<目标类型>(表达式);
const_cast<目标类型>(表达式);
reinterpret_cast<目标类型>(表达式);
dynamic_cast<目标类型>(表达式);
1. static_cast
static_cast是最常用的C++风格的强制类型转换,主要是为了执行那些较为合理的强制类型转换.
1)用于内置数据类型之间的转换
C风格:编译器可能会提示警告信息。
static_cast:不会提示警告信息。
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
int ii = 3;
long ll = ii; // 绝对安全,可以隐式转换,不会出现警告。
double dd = 1.23;
long ll1 = dd; // 可以隐式转换,但是,会出现可能丢失数据的警告。
long ll2 = (long)dd; // C风格:显式转换,不会出现警告。
long ll3 = static_cast<long>(dd); // C++风格:显式转换,不会出现警告。
cout << "ll1=" << ll1 << ",ll2=" << ll2 << ",ll3=" << ll3 << endl;
}
2)用于指针之间的转换
C风格:可用于各种类型指针之间的转换。
static_cast:各种类型指针之间的不允许转换,必须借助void*类型作为中间介质。
#include <iostream>
using namespace std;
void func(void* ptr) { // 其它类型指针 -> void *指针 -> 其它类型指针
double* pp = static_cast<double*>(ptr);
}
int main(int argc, char* argv[])
{
int ii = 10;
//double* pd1 = ⅈ // 错误,不能隐式转换。
double* pd2 = (double*) ⅈ // C风格,强制转换。
//double* pd3 = static_cast<double*>(&ii); // 错误,static_cast不支持不同类型指针的转换。
void* pv = ⅈ // 任何类型的指针都可以隐式转换成void*。
double* pd4 = static_cast<double*>(pv); // static_cast可以把void *转换成其它类型的指针。
func(&ii);
}
3)不能转换掉expression的const或volitale属性
#include <iostream>
int main(int argc, char* argv[])
{
int temp = 10;
const int* a_const_ptr = &temp;
int* b_const_ptr = static_cast<int*>(a_const_ptr); // const int* -> int* 无效
const int a_const_ref = 10;
int& b_const_ref = static_cast<int&>(a_const_ref); // const int& -> int& 无效
volatile int* a_vol_ptr = &temp;
int* b_vol_ptr = static_cast<int*>(a_vol_ptr); // volatile int* -> int* 无效
volatile int a_vol_ref = 10;
int& b_vol_ref = static_cast<int&>(a_vol_ref); // volatile int& -> int& 无效
}
2.const_cast
static_cast不能丢掉指针(引用)的const和volitale属性,const_cast可以。
示例:
#include <iostream>
using namespace std;
void func(int *ii) {}
int main(int argc, char* argv[])
{
const int *aa=nullptr;
int *bb = (int *)aa; // C风格,强制转换,丢掉const限定符。
int* cc = const_cast<int*>(aa); // C++风格,强制转换,丢掉const限定符。
func(const_cast<int *>(aa));
}
3.reinterpret_cast
static_cast不能用于转换不同类型的指针(引用)(不考虑有继承关系的情况),reinterpret_cast可以。
reinterpret_cast的意思是重新解释,能够将一种对象类型转换为另一种,不管它们是否有关系。
语法:reinterpret_cast<目标类型>(表达式);
<目标类型>和(表达式)中必须有一个是指针(引用)类型。
reinterpret_cast不能丢掉(表达式)的const或volitale属性。
应用场景:
1)reinterpret_cast的第一种用途是改变指针(引用)的类型。
2)reinterpret_cast的第二种用途是将指针(引用)转换成整型变量。整型与指针占用的字节数必须一致,否则会出现警告,转换可能损失精度(注:VS中指针变量为8Byte,即64位)。
3)reinterpret_cast的第三种用途是将一个整型变量转换成指针(引用)。
示例:
#include <iostream>
using namespace std;
void func(void* ptr) {
long long ii = reinterpret_cast<long long>(ptr);
cout << "ii=" << ii << endl;
}
int main(int argc, char* argv[])
{
long long ii = 10;
func(reinterpret_cast<void *>(ii));
}
4.dynamic_cast
dynamic_cast一般用于多态.
基类指针可以指向派生类对象,如何知道基类指针指向的是哪种派生类的对象呢?(想调用派生类中的非虚函数)。
dynamic_cast运算符用指向基类的指针来生成派生类的指针,它不能回答“指针指向的是什么类的对象”的问题,但能回答“是否可以安全的将对象的地址赋给特定类的指针”的问题。
语法:派生类指针 = dynamic_cast<派生类类型 *>(基类指针);
如果转换成功(基类指针指向的就是该派生类对象),dynamic_cast返回对象的地址,如果失败,返回nullptr。
注意:
1)dynamic_cast只适用于包含虚函数的类。
2)dynamic_cast可以将派生类指针转换为基类指针,但这种画蛇添足的做法没有意义。
3)dynamic_cast可以用于引用,但是,没有与空指针对应的引用值(在 C++ 标准中,引用不能被赋值为nullptr,
因为引用必须总是引用一个有效的对象,而引用的本质--指针常量可以初始化为nullptr,但一般无意义.)
,如果转换请求不正确,会出现bad_cast异常。
示例:
#include <iostream> // 包含头文件。
using namespace std; // 指定缺省的命名空间。
class Hero // 英雄基类
{
public:
int viability; // 生存能力。
int attack; // 攻击伤害。
virtual void skill1() { cout << "英雄释放了一技能。\n"; }
virtual void skill2() { cout << "英雄释放了二技能。\n"; }
virtual void uskill() { cout << "英雄释放了大绝招。\n"; }
};
class XS :public Hero // 西施派生类
{
public:
void skill1() { cout << "西施释放了一技能。\n"; }
void skill2() { cout << "西施释放了二技能。\n"; }
void uskill() { cout << "西施释放了大招。\n"; }
void show() { cout << "我是天下第一美女。\n"; }
};
class HX :public Hero // 韩信派生类
{
public:
void skill1() { cout << "韩信释放了一技能。\n"; }
void skill2() { cout << "韩信释放了二技能。\n"; }
void uskill() { cout << "韩信释放了大招。\n"; }
};
class LB :public Hero // 李白派生类
{
public:
void skill1() { cout << "李白释放了一技能。\n"; }
void skill2() { cout << "李白释放了二技能。\n"; }
void uskill() { cout << "李白释放了大招。\n"; }
};
int main()
{
// 根据用户选择的英雄,施展一技能、二技能和大招。
int id = 0; // 英雄的id。
cout << "请输入英雄(1-西施;2-韩信;3-李白。):";
cin >> id;
// 创建基类指针,让它指向派生类对象,用基类指针调用派生类的成员函数。
Hero* ptr = nullptr;
if (id == 1) { // 1-西施
ptr = new XS;
}
else if (id == 2) { // 2-韩信
ptr = new HX;
}
else if (id == 3) { // 3-李白
ptr = new LB;
}
if (ptr != nullptr) {
ptr->skill1();
ptr->skill2();
ptr->uskill();
// 如果基类指针指向的对象是西施,那么就调用西施的show()函数。
//if (id == 1) {
// XS* pxs = (XS *)ptr; // C风格强制转换的方法,程序员必须保证目标类型正确。
// pxs->show();
//}
XS* xsptr = dynamic_cast<XS*>(ptr); // 把基类指针转换为派生类。
if (xsptr != nullptr) xsptr->show(); // 如果转换成功,调用派生类西施的非虚函数。
delete ptr;
}
// 以下代码演示把基类引用转换为派生类引用时发生异常的情况。
/*HX hx;
Hero& rh = hx;
try{
XS & rxs= dynamic_cast<XS &>(rh);
}
catch (bad_cast) {
cout << "出现了bad_cast异常。\n";
}*/
}
标签:类型转换,const,int,C++,cast,强制,ptr,指针
From: https://blog.csdn.net/qq_74224788/article/details/145019416