C++ 类型转换与异常处理全解析

一、C++ 类型转换

C++ 提供了 4 种显式类型转换方式,分别适用于不同场景,相比 C 语言的隐式转换更安全、可读性更高。

1. 静态类型转换(static_cast)

核心用途:基本数据类型转换、有继承关系的类指针 / 引用转换(编译期检查)。

(1)基本数据类型转换
cpp 复制代码
void test01() {
	char a = 'a ';
	//char->double;
	//static_cast<要转到的类型>(将谁转换)
	double d = static_cast<double> (a);
	double d1 = (double)a;
}
(2)派生类与基类指针转换
复制代码
cpp 复制代码
class Father{

};
class Son :public Father {

};
class Other {
};
void test02() {
	Father* f = NULL;
	Son* s = NULL;
	//Son s1=static_cast<Son*>(f);向下转化不安全
	Father* f1 = static_cast<Father*> (s);
	//Other* o = static_cast<Other*> (s);没有继承关系的类不能转化

}
(3)引用转换
复制代码
cpp 复制代码
void test03() {
    Father f;
    Son s;
    Father& ref_f = f;
    Son& ref_s = s;
    // 子类引用转父类引用
    static_cast<Father&>(ref_s);
}

}

2. 动态类型转换(dynamic_cast)

核心用途:多态类(含虚函数)的指针 / 引用转换(运行期检查),仅支持有继承关系的类。

复制代码
cpp 复制代码
// 基础类型不能用dynamic_cast
// void test04() {
//     char a = 'a';
//     dynamic_cast<double>(a); // 编译报错
// }

class Father02 {
public: 
    virtual void test() {}; // 虚函数,开启多态
};
class Son02 :public Father02 {
public:
    virtual void test() {};
};

void test05() {
    Father02* f = new Son02; // 父类指针指向子类对象(多态)
    // 向下转换安全,运行期检查类型
    Son02* s = dynamic_cast<Son02*>(f);
}

3. 常量类型转换(const_cast)

核心用途 :移除 / 添加变量的const属性,仅针对指针 / 引用。

cpp 复制代码
void test06() {
	const int* p = NULL;
	//const->不带const
	int* newP = const_cast<int*>(p);
	int* pp = NULL;
	const int* newPP = const_cast<const int*>(pp);
}

4. 重新解释转换(reinterpret_cast)

核心用途:任意类型间的二进制位重新解释(极其不安全,慎用)。

cpp 复制代码
void test07() {
    int a = 10;
    // 整数转指针
    int* p = reinterpret_cast<int*>(a);
    
    Father* f = NULL;
    // 无继承关系的类指针转换
    Other* o = reinterpret_cast<Other*>(f);
}

二、C++ 异常处理详解

C 语言通过返回值处理错误存在诸多缺陷,C++ 的异常机制可更优雅地处理程序运行时错误。

1. 为什么需要异常?

C 语言返回值处理错误的问题:

  • 返回值语义不明确(比如 - 1 可能代表多种错误);

  • 仅能返回单一信息,无法携带详细错误描述;

  • 返回值可被忽略,导致错误未被处理。

cpp 复制代码
// C风格错误处理示例
int printArray(int arr[], int len) {
    if (arr == NULL) return -1; // 空指针错误
    if (len == 0) return 0;    // 空数组错误
    return 1;
}

void test() {
    int* arr = NULL;
    int len = 0;
    printArray(arr, len); // 忽略返回值,错误未处理
}

2. 异常基础语法

异常处理三要素:try(监控可能出错的代码)、throw(抛出异常)、catch(捕获并处理异常)。

cpp 复制代码
#include <iostream>
using namespace std;

int func(int a, int b) {
    if (b == 0) {
        // 抛出int类型异常
        throw 10;
    }
    return a / b;
}

void test() {
    int a = 10;
    int b = 0;
    // 监控异常
    try {
        func(a, b);
        cout << "异常抛出后,此行不会执行" << endl;
    }
    // 捕获int类型异常
    catch (int) {
        cout << "除数不能为0" << endl;
    }
}

3. 异常的优势

(1)携带丰富的错误信息(抛出对象)
cpp 复制代码
class ErrorInfo {
public:
    void printError() {
        cout << "错误详情:除数不能为0" << endl;
    }
};

int func(int a, int b) {
    if (b == 0) {
        ErrorInfo err;
        throw err; // 抛出对象,携带更多信息
    }
    return a / b;
}

void test() {
    try {
        func(10, 0);
    }
    catch (ErrorInfo err) {
        err.printError();
    }
}
(2)异常无法忽略(忽略则程序崩溃)

若未捕获异常,程序会直接终止,强制开发者处理错误(相比返回值更严格)。

(3)异常可向上传递
cpp 复制代码
void test() {
    try {
        func(10, 0);
    }
    catch (double s) {
        // 不处理,向上抛给调用者
        throw;
    }
}

int main() {
    try {
        test();
    }
    catch (double d) {
        cout << "main函数捕获异常:" << d << endl;
    }
    return 0;
}

4. 异常的高级特性

(1)严格类型匹配 & 万能捕获

异常捕获需严格匹配类型,catch(...)可捕获任意类型异常(兜底处理)。

cpp 复制代码
void func(int a, int b) {
    if (b == 0) {
        throw 'a'; // 抛出char类型异常
    }
}

void test() {
    try {
        func(10, 0);
    }
    // 精准捕获
    // catch (int) {}
    // 万能捕获
    catch (...) {
        cout << "捕获未知类型异常" << endl;
    }
}
(2)异常接口声明

限制函数可抛出的异常类型(Qt 等框架常用):

cpp 复制代码
// 仅允许抛出int/char类型异常
void func() throw(int, char) {
    throw 10.0; // 抛出double异常,框架会拦截
}
(3)栈解旋

抛出异常后,函数栈上的局部对象会被自动析构(释放资源):

cpp 复制代码
class Maker {
public:
    Maker() { cout << "Maker构造" << endl; }
    ~Maker() { cout << "Maker析构" << endl; }
};

void func() {
    Maker m; // 栈上对象
    throw m; // 抛出异常,m会被析构(栈解旋)
    cout << "此行不会执行" << endl;
}

void test() {
    try {
        func();
    }
    catch (Maker) {
        cout << "捕获异常" << endl;
    }
}
(4)异常对象的生命周期

推荐使用引用捕获匿名对象,减少拷贝,仅生成 1 个对象:

复制代码
cpp 复制代码
// 最优方式:仅生成1个对象
void func() {
    throw Maker(); // 匿名对象
}

void test() {
    try {
        func();
    }
    catch (Maker& m) { // 引用捕获,无拷贝
        cout << "捕获异常" << endl;
    }
}
(5)异常的多态应用

通过基类捕获子类异常,统一处理不同类型错误:

cpp 复制代码
// 异常基类
class BaseError {
public:
    virtual void printError() = 0; // 纯虚函数
};

// 空指针异常
class NullError : public BaseError {
public:
    virtual void printError() {
        cout << "空指针异常" << endl;
    }
};

// 越界异常
class OutError : public BaseError {
public:
    virtual void printError() {
        cout << "数组越界异常" << endl;
    }
};

void func(int a) {
    if (a == 0) throw NullError();
    if (a > 100) throw OutError();
}

void test() {
    try {
        func(200);
    }
    catch (BaseError& err) { // 基类引用捕获子类
        err.printError(); // 多态调用
    }
}

三、总结

  1. 类型转换:static_cast(编译期,通用)、dynamic_cast(运行期,多态类)、const_cast(修改 const)、reinterpret_cast(二进制重解释,慎用);

  2. 异常处理:通过try-catch-throw处理错误,相比返回值更严格、信息更丰富;

  3. 最佳实践:异常对象用引用捕获、利用多态统一处理异常、避免滥用reinterpret_cast

相关推荐
zhangfeng11331 小时前
htc 中minconda 明明安装了 Python 3.10显示 python 3.8 因为 `conda activate` 没有真正切换成功
开发语言·python·conda
十五年专注C++开发2 小时前
C++17之类模板实参自动推导CTAD
开发语言·c++·聚合初始化·catd
iCxhust2 小时前
C# 程序,实现二进制文件十六进制查看器,支持按行定位
开发语言·单片机·嵌入式硬件·c#·微机原理·8086最小系统·8088单板机
咕噜企业签名分发-淼淼2 小时前
浅谈云服务器在后端托管与签名分发场景中的应用价值
开发语言·php
在繁华处2 小时前
Java从零到熟练(八):泛型与注解
java·开发语言·python
SilentSamsara2 小时前
命令行工具开发:Click/Typer + 打包为独立二进制
linux·服务器·开发语言·前端·python·青少年编程·fastapi
Ulyanov2 小时前
深入QML滑块与进度控制:构建动态数据可视化界面:QML+PySide6现代开发入门(六)
开发语言·python·算法·ui·信息可视化·雷达电子对抗仿真
星马梦缘2 小时前
ACM笔记 学习版本
数据结构·c++·算法
zyl837212 小时前
Python 函数、模块、异常处理 超详细入门教程
开发语言·windows·python
苏州IT威翰德2 小时前
苏州IT基础架构IQ/OQ/PQ确认服务 | 服务器网络验证
开发语言·php