一、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(); // 多态调用
}
}
三、总结
-
类型转换:
static_cast(编译期,通用)、dynamic_cast(运行期,多态类)、const_cast(修改 const)、reinterpret_cast(二进制重解释,慎用); -
异常处理:通过
try-catch-throw处理错误,相比返回值更严格、信息更丰富; -
最佳实践:异常对象用引用捕获、利用多态统一处理异常、避免滥用
reinterpret_cast。