类型转换static_cast,dynamic_cast,const_cast,reinterpret_cast等

一、隐式类型转换

系统自动进行,不需要程序开发人员介入。

int m = 3 +45.6; //把小数部分截掉,也属于隐式类型转换的一种行为。

doublen = 3 +45.6;

二、显示类型转换(强制类型转换)

int k = 5 % 3.2; // 语法错

int k = 5 %(int)3.2; // OK,C语言风格的强制类型转换

int k = 5 % int(3.2); // 函数风格的强制类型转换(C语言风格的强制类型转换)

c++强制类型转换分为4中:我们现在写程序应该使用c++风格的强制类型转换。

这4种强制类型转换,分别用于不同的目的,每一个都有一个不同的名字。提供4中类的目的:提供更丰富的含义和功能,更好的类型检查机制,方便代码的熟悉和维护

a)static_cast

b)dynamic_cast

c)const_cast

d)reinterpret_cast

这四个强制类型转换都被称呼为“命名的强制类型转换”

通用形式

强制类型转换名(express)

强制类型转换名是上边a,b,c,d四个名字之一

type:换换的目标类型

express:你要转换的值

2.1static_cast

static_cast:静态转换,大家就理解成“正常转换”,编译的时候就会进行类型转换的检查

代码中要保证转换的安全性和正确性,static_cast含义跟c语言中的强制类型转换这种差不多

c风格的强制类型转换,以及编译器能够进行的隐式类型转换,都可以用static_cast类显示完成

可用于:

a)相关类型转换,比如整形和实型之间的转换:

double f = 100.34f;
int i = (int)f; // c风格的
int i2 = static(f) // c++风格的类型转换

b)子类转成父类类型(继承关系),也能用这个static_cast转

class A {};
class B : public A {};

B b
A a = static_cast(b); // 把子类转成父类的对象

c)void*与其他类型指针之间的转换,void*:无类型指针:可以指向任意类型指针(万能指针)

int i = 10;
int *p = &i;
void *q = static_cast(p); // int *转成void *,或者 void* q = p;
int *db = static_cast(q); // 需要使用static_cast才可以将void* 转为 int *

不可用于:

a)一般不能用于指针类型之间的转换比如int*转double*,float*转double*等。

d.static_cast总结:

  1. 编译器隐式执行的任何类型转换都可以由static_cast完成

  2. 当一个较大的算术类型赋值给较小的类型时,可以用static_cast进行强制转换。

  3. 可以将void*指针转换为某一类型的指针

  4. 可以将基类指针转换为派生类指针

#include 
using namespace std;

class Base {
};

class Derived :public Base {
};

int main() {
    Base* base = new Derived;
    Derived* derive = static_cast(base);
    //Derived* derive = dynamic_cast(base);    // 错误的,原因:因为Base没有虚函数
}

2.2dynamic_cast

主要应用运行时类型识别的检查。主要用来父类型和子类型之间转换(父类型指针指向子类型对象,然后用dynamic_cast把父指针类型往子指针类型转)

2.3const_cast

a)去除指针或者引用的const属性。该转换能够将const性质转换掉。

编译时进行类型检查

const int ai = 90;
int ai2 = const_cast(ai); // ai不是指针也不是引用不能转
const int *pai = &ai;
int *pai2 = const_cast(pai); // 语法正确
*pai2 = 120; // 这种写值行为是属于一种未定义行为。大家不要这么干
cout << ai << endl;
cout << *pai << endl;

// c风格强制类型转换
const int ai = 90;
int *pai = (int*)&ai;
*pai = 120; // 未定义行为
cout << ai << endl;
cout << *pai << endl;

#include 
 
using namespace std;
 
void func(int& val) {
	cout << "func: " << val << endl;
}
 
 
//const_cast 用来移除对象的常量性
//const_cast一般用来用于指针或者引用
//const_cast去除常量性,不是为了修改他指定的内容
//const_cast去除常量性,为了函数能接受实参
 
int main() {
	
	const int val = 100;
	//int n = const_cast(val);
	//const_cast一般用于指针或者引用
	
	//int* p = &val;
	int* p = const_cast(&val);
	*p = 200;
	cout << val << endl;  // val 还是 100, 改变临时对象值
	cout << "addr p: " << p << endl;
	cout << "addr val: " << &val << endl;
	
 
	const int val2 = 200;
	//int& refval2 = val2;	
	int& refval2 = const_cast(val2);
	refval2 = 300;
	cout << "val2: " << val2 << endl;  // 改变临时对象值
	//func(val2);
	func(const_cast(val2));
	return 0;
}

b)const_cast总结

  1. 用来移除对象的常量性(cast away the constness)

  2. const_cast一般用于指针或者引用

  3. 使用const_cast去除const限定的目的不是为了修改它的内容

  4. 使用const_cast去除const限定,通常是为了函数能够接受这个实际参数

2.4reinterpret_cast

    reinterpret:重新解释。(将操作系统内容解释为另一种不同的类型【能把操作数的类型都转了】)

处理无关类型的转换。也就是两个转换类型之间没有什么关系。就等于可以乱转,自由转。

常用于如下两种转换:

a)将一个整型(地址)转换成指针,一种类型指针转换成另一种类型指针,按照转换后的内容重新解释内存中的内容;

b)也可以从一个指针类型转换成一个整型

int i = 10;
int *pi = &i;
int *p2 = reinterpret_cast(&i);
char *pc = reinterpret_cast(pi); // 任意指针类型之间的转换

int i = 10;
int *pi = &i;
void *pvoid = reinterpret_cast(&i);
int *pi2 = reinterpret_cast(pvoid);

被认为是危险的类型转换,随便转,怎么搞都行,编译器都不报错

int iv1 = 100;
long long lv1 = 8898899400; // 8 字节的 十六进制: 2 126A 6DC8
int*piv1 = (int*)iv1; // c语言风格
int *piv2 = reinterpret_cast(iv1);
piv2 = reinterpret_cast(lv1);  // 整型转指针
long long ne = reinterpret_cast(piv2); // 指针转整型

c.reinterpret_cast总结

通常为操作数的位模式提供较低层的重新解释”也就是说将数据以二进制存在形式的重新解释。

三.总结

(1)强制类型转换,不建议使用。强制类型转换能够抑制编译器报错

(2)学习目的:认识这些类型转换符,方便大家阅读别人代码。

(3)资料说:reinterpret_cast危险。使用const_cast意味着设计缺陷。

(4)如果实在需要使用类型转换,不要再使用c语言风格的类型转换了,而用c++风格的类型转换

(5)一般static_cast和reinterpret_cast就能够很好的取代c语言风格的类型转换

 

你可能感兴趣的:(C++奇技淫巧)