Day 12:自定义异常与函数模板
本节代码位置:
2-代码/day12-自定义异常/69-自定义异常类型示例.cpp
2-代码/day12-自定义异常/70-函数模板示例.cpp
2-代码/day12-自定义异常/70-函数模板练习.cpp
1、自定义异常
C++ 标准库提供了 std::exception 作为常用异常基类。需要表达自己的错误类型时,可以公开继承它,并重写 what()。
class MyException : public std::exception
{
public:
MyException(const char *errmsg) : errmsg(errmsg) {}
const char *what() const noexcept override
{
return errmsg;
}
private:
const char *errmsg;
};
这里的 errmsg 保存错误描述;what() 是给调用者读取错误信息的统一接口。
2、抛出和捕获异常
发现错误时使用 throw 抛出异常对象:
void foo()
{
throw MyException("this is a test!");
}
调用处用 try 包住可能出错的代码,再用 catch 处理:
try
{
foo();
}
catch (const std::exception &err)
{
cout << "err: " << err.what() << endl;
}
虽然抛出的是 MyException,但它继承自 std::exception,所以可以用基类引用捕获。这样既能处理多种标准异常,又能保留派生类的真实异常信息。
3、异常使用要点
1. throw 用于抛出异常对象。
2. try 中放可能发生异常的代码。
3. catch 负责匹配并处理异常。
4. 异常对象通常按值抛出,按 const 引用捕获。
5. 按引用捕获能避免不必要的拷贝,也能避免对象切片。
6. what() 返回 const char*;noexcept 表示该函数不会再抛出异常。
异常适合处理“当前函数无法在原地恢复”的错误。函数发现问题后把异常交给上层,上层决定记录、提示、重试还是退出。
4、函数模板
函数模板把算法逻辑写一次,再由编译器根据实参类型生成对应的函数。
template <typename T>
void Swap(T &a, T &b)
{
T temp = a;
a = b;
b = temp;
}
调用时会自动推导模板参数:
int x = 1;
int y = 2;
Swap(x, y); // T 推导为 int
double a = 1.1;
double b = 2.2;
Swap(a, b); // T 推导为 double
同一个 Swap 可以用于多种类型,因此不必分别写 SwapInt、SwapDouble。
5、多个模板参数与显式指定
template <typename T1, typename T2>
T1 sum(T1 a, T2 b)
{
return a + b;
}
cout << sum<double, double>(1, 2.2) << endl;
sum 有两个类型参数。大多数情况下编译器可以推导;当想控制返回类型或推导不符合预期时,也可以像示例一样显式写出模板实参。
6、数组长度作为模板参数
template <typename T, size_t N>
int findValue(const T (&arr)[N], const T &value)
{
for (size_t i = 0; i < N; ++i)
{
if (arr[i] == value)
return static_cast<int>(i);
}
return -1;
}
T 表示元素类型,N 表示数组长度。参数 const T (&arr)[N] 是“数组的引用”,调用时编译器会自动得到长度,不需要再额外传数组大小。
7、Day12 总结
1. 自定义异常可继承 std::exception,并重写 what()。
2. 用 throw 抛异常,用 try/catch 处理异常。
3. 捕获异常优先使用 const 基类引用。
4. 函数模板让一套算法支持多种数据类型。
5. 模板参数既可以是类型,也可以是编译期常量,例如数组长度 N。
一句话记忆:异常负责把错误交给调用方处理;函数模板负责把重复算法写成可复用的通用函数。






Comments | NOTHING