C++中的四种强制类型转换

1、dynamic cast

2、const_cast

3、static_cast

4、reinterpret_cast

5、static_cast和reinterpret_cast的区别

6、关于算术提升的一些坑


1、dynamic cast

    dynamic_cast操作符将基类类型对象的引用或指针转换为同一继承层次中其它类型的引用或指针。与dynamic_cast一起使用的指针必须是有效的,它必须为0或指向一个对象。与另外三种强制类型转换不同,dynamic_cast涉及运行时类型检查。如果绑定到引用或指针的对象不是目标类型的对象,则dynamic_cast失效。如果转换到指针类型的dynamic_cast失败,则dynamic_cast的结果是0值;如果转换到引用类型的dynamic_cast失败,则抛出一个bad_cast类型的异常。

  • 指针转换语法:dynamic_cast<*Derived> (*Base)
  • 引用转换语法:dynamic_cast<Type&> (val);

2、const_cast

    const_cast的作用如下:

  • 将转换掉表达式的const性质;
  • 只有使用const_cast才能将const性质性质转化掉,试图使用其他三种形式的强制转换都会导致编译时的错误;
  • 除了添加const或删除const特性,使用const_cast符来执行其他任何类型的转换都会引起编译错误。

  示例:

int main()
{
    const int constant = 26;
    const int* const_p = &constant;
    int* modifier = const_cast<int*>(const_p);
    *modifier = 3;
    cout<< "constant:  "<<constant<<endl;
    cout<<"*modifier:  "<<*modifier<<endl;
    system("pause");
}

输出:
26
3

     对声明为const的变量来说,常量就是常量,任你各种转化,常量的值就是不会变。这是C++的一个承诺。那既然const变量的值是肯定不会发生变化的,还需要这个const_cast类型转化有何用?这就引出了const_cast的最常用用法:如果有一个函数,它的形参是non-const类型变量,而且函数不会对实参的值进行改动,这时我们可以使用类型为const的变量来调用函数,此时const_cast就派上用场了。

void InputInt(int * num)
{
    cout<<*num<<endl;
}
int main()
{
    const int constant = 21;
    //InputInt(constant); //error C2664: “InputInt”: 不能将参数 1 从“const int”转换为“int *”
    InputInt(const_cast<int*>(&constant));
    system("pause");
}

总结:const_cast绝对不是为了改变const变量的值而设计的,在函数参数的传递上const_cast的作用才显现出来。 

3、static_cast

    编译器隐式执行的任何类型转换都可以由static_cast显式完成。当需要将一个较大的算术类型赋值给较小类型时,使用强制类型转换非常有用。此时强制类型转换告诉程序的读者和编译器:我们知道并且不关心潜在的精度损失。对于从一个较大的算术类型到一个较小类型的赋值,编译器通常会产生警告。当我们显式提供强制类型转换时,警告信息将会被关闭。比如:

double d = 97.0;
char ch = static_cast<char> d;

4、reinterpret_cast

    reinterpret_cast通常为操作数的位模式提供较低层次的重新解释,它从二进制重新映射解释,不会进行类型安全检查,甚至可以在两个无关的类型之间进行转换。比如:

int main() {
	int a = 10;
	int *p = &a;
	int b = reinterpret_cast<int>(p);
	cout << b << endl;
	return 0;
}

    使用reinterpret_cast甚至可以从一个指针类型转为一个int类型,不进行类型安全检查,这个转换是非常安全的。 

5、static_cast和reinterpret_cast的区别

  • reinterpret_cast可以转换任意一个32bit整数,包括所有的指针和整数。可以把任何整数转成指针,也可以把任何指针转成整数,以及把指针转化为任意类型的指针,威力最为强大!但不能将非32bit的实例转成指针。总之,只要是32bit的东东,怎么转都行。
  • static_cast和dynamic_cast可以执行指针到指针的转换,或实例本身到实例本身的转换,但不能在实例和指针之间转换。static_cast只能提供编译时的类型安全,而dynamic_cast可以提供运行时类型安全。

    实例1;

int main() {
	int a = 10;
	int *p = &a;
	int b = reinterpret_cast<int>(p);          //编译通过
	float *q = reinterpret_cast<float*>(p);    //编译通过
    
	//int b = static_cast<int>(p);       编译不通过:error C2440: “static_cast”: 无法从“int *”转换为“int”
	//float *q = static_cast<float*>(p); 编译不通过:error C2440: “static_cast”: 无法从“int *”转换为“float *”

	cout << q << endl;
	cout << b << endl;
	return 0;
}

     实例2:

class A 
{ 
public:
	A(int m = 1) :m(m) {}
	int m; 
};
class B 
{
public:
	B(int m = 2) :m(m) {}
	int m; 
};
class C :public A, public B 
{
public:
	C() {}
};
int main() {
	C c;
	cout << &c << endl;
	cout << sizeof(c) << endl<<endl;

	B *b1 = reinterpret_cast<B*>(&c);
	cout << b1 << endl;
	cout << sizeof(*b1) << endl;
	cout <<"b1:m = "<< b1->m << endl<<endl;

	B *b2 = static_cast<B*>(&c);
	cout << b2 << endl;
	cout << sizeof(*b2)<<endl;
	cout <<"b2:m = "<< b2->m<<endl;

	return 0;
}
输出:
00F3FC6C
8

00F3FC6C
4
b1:m = 1

00F3FC70
4
b2:m = 2

    可以看出,使用reinterpret_cast从派生类到基类的转换时,指针的地址并没改变。而使用static_cast从派生类到基类的转换时,指针的地址发生了改变,指针此时变成一个指向基类的指针,指针的地址仍然位于派生类的地址空间中。

6、关于算术提升的一些坑

(1)当从一个精度较高的类型(比如int、unsigned int)赋值给一个精度较低的类型(如short、unsigned short)时,精度较低的类型直接从高精度类型的低字节截取即可。

(2)但是反过来,当从一个精度较低的类型(如short、unsigned short)赋值给一个精度较高的类型(比如int、unsigned int short)时,精度较高的类型的高字节部分用什么填充呢,这里要分为两种情况:

  • 如果低精度类型的第一个bit位为1,那么高精度类型的所有高字节部分用1填充;
  • 如果低精度类型的第一个bit位为0,那么高精度类型的所有高字节部分用0填充。
int main() {
	char a1 = 54;	
	bitset<8> bit_a1(a1);
	cout << "bit_a1:"<<bit_a1<< endl;
	unsigned short b1 = a1;
	cout << "b1:"<<b1 << " bit_b1:";
	bitset<16> bit_b1(b1);
	cout << bit_b1 << endl<<endl;
	

	char a2 = 130;
	bitset<8> bit_a2(a2);
	cout << "bit_a2:"<< bit_a2 << endl;
	unsigned short b2 = a2;
	cout << "b2:"<<b2 << " bit_b2:";
	bitset<16> bit_b2(b2);
	cout << bit_b2 << endl;
	return 0;
}

输出:
bit_a1:00110110
b1:54 bit_b1:0000000000110110

bit_a2:10000010
b2:65410 bit_b2:1111111110000010


int main() {
	char a = 127;
	char b = 128;
	unsigned short c = 200;
	cout << a + c << endl;                   //类型不同的相加得到的结果为int
	cout << typeid(a + c).name() << endl;
	cout << b + c << endl;
	cout << typeid(a + b).name() << endl;    //类型相同的相加得到的结果也为int
	return 0;
}
输出:
327
int
72
int

 

### C++四种强制类型转换详解 C++ 提供了四种专门用于类型转换的操作符,分别是 `static_cast`、`dynamic_cast`、`const_cast` 和 `reinterpret_cast`。每种操作符都有其特定的应用场景和限制条件。 --- #### 1. **`static_cast`** `static_cast` 是一种静态类型转换操作符,主要用于基本数据类型之间的转换以及类层次结构中的向上或向下类型转换。它的特点是编译期检查安全性较高,但在运行时不进行额外验证。 ##### 使用场景: - 基本数据类型间的转换(如 `int` 到 `float`)。 - 枚举类型到整数类型的转换。 - 指针或引用的上下转型(前提是存在继承关系)。 ##### 示例代码: ```cpp double d = 3.14; int i = static_cast<int>(d); // 将 double 转换为 int ``` 需要注意的是,如果尝试将基类指针转换为派生类指针而实际对象并非派生类实例,则可能导致未定义行为[^1]。 --- #### 2. **`dynamic_cast`** `dynamic_cast` 主要用于类层次结构中的安全向下转型。它是唯一能够在运行时检测类型的安全性的方式,并且仅适用于带有虚函数的类(即多态类)。如果目标类型不匹配,返回的结果取决于是否为指针或引用:对于指针,返回 `nullptr`;对于引用,抛出异常。 ##### 使用场景: - 安全地将基类指针或引用转换为派生类指针或引用。 - 运行时类型识别(RTTI)。 ##### 示例代码: ```cpp Base* basePtr = new Derived(); Derived* derivedPtr = dynamic_cast<Derived*>(basePtr); if (derivedPtr != nullptr) { std::cout << "成功转换!" << std::endl; } else { std::cout << "转换失败!" << std::endl; } ``` 注意,只有当基类包含至少一个虚函数时,`dynamic_cast` 才能正常工作[^5]。 --- #### 3. **`const_cast`** `const_cast` 用于移除变量的 `const` 或 `volatile` 属性。这是唯一的用途,因此应谨慎使用,因为它可能破坏常量保护机制。 ##### 使用场景: - 移除指针或引用的只读属性以便修改原对象。 - 解决某些遗留 API 对非 `const` 参数的要求。 ##### 示例代码: ```cpp const int value = 10; int& modifiableValue = const_cast<int&>(value); modifiableValue = 20; // 修改原来标记为 const 的值 ``` 尽管语法上允许这样做,但直接修改原始 `const` 数据可能会引发未定义行为[^3]。 --- #### 4. **`reinterpret_cast`** `reinterpret_cast` 是最危险的一种类型转换,它直接对底层比特模式重新解释,绕过任何语义上的约束。由于缺乏安全性保障,除非绝对必要,否则不应频繁使用此操作符。 ##### 使用场景: - 将指针转换为无关类型(例如从某种指针转为另一种类别的指针)。 - 把指针当作整数值存储后再恢复回来。 ##### 示例代码: ```cpp int number = 42; void* rawPointer = &number; int* originalPointer = reinterpret_cast<int*>(rawPointer); std::cout << *originalPointer << std::endl; // 输出 42 ``` 重要提示:此类转换高度依赖硬件架构细节,跨平台兼容性和稳定性较差。 --- ### 各种转换的区别总结 | 特性 | `static_cast` | `dynamic_cast` | `const_cast` | `reinterpret_cast` | |---------------------|----------------------|-----------------------|-----------------------|------------------------| | 是否需要 RTTI | 不需要 | 需要 | 不需要 | 不需要 | | 应用范围 | 广泛适用 | 类型间安全转化 | 只处理 `const/volatile` | 危险低级重解 | | 性能开销 | 较少 | 更大 | 很小 | 几乎无 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值