介绍
在本实验中,你将学习 C++ 中异常处理的基本概念。你将从理解如何抛出和捕获基本异常开始,异常是处理程序中运行时错误或意外情况的一种方式。然后,你将探索 try
、catch
和 throw
关键字的使用,以及标准异常类如 std::exception
。此外,你还将学习如何定义自定义异常类,并为不同的异常类型实现多个 catch
块。最后,你将探索使用嵌套的 try-catch
块来处理程序中不同层次的异常。
在本实验中,你将学习 C++ 中异常处理的基本概念。你将从理解如何抛出和捕获基本异常开始,异常是处理程序中运行时错误或意外情况的一种方式。然后,你将探索 try
、catch
和 throw
关键字的使用,以及标准异常类如 std::exception
。此外,你还将学习如何定义自定义异常类,并为不同的异常类型实现多个 catch
块。最后,你将探索使用嵌套的 try-catch
块来处理程序中不同层次的异常。
在这一步骤中,你将学习 C++ 中异常处理的基本概念,重点是如何抛出和捕获基本异常。异常是处理程序中运行时错误或意外情况的一种方式。
打开 WebIDE,在 ~/project
目录下创建一个名为 basic_exceptions.cpp
的新文件:
touch ~/project/basic_exceptions.cpp
将以下代码添加到 basic_exceptions.cpp
中:
#include <iostream>
#include <stdexcept>
int divide(int numerator, int denominator) {
// Throw an exception if denominator is zero
if (denominator == 0) {
throw std::runtime_error("Division by zero is not allowed!");
}
return numerator / denominator;
}
int main() {
try {
// Attempt a normal division
int result1 = divide(10, 2);
std::cout << "10 / 2 = " << result1 << std::endl;
// Attempt division by zero
int result2 = divide(10, 0);
std::cout << "This line will not be executed" << std::endl;
}
catch (const std::exception& e) {
// Catch and handle the exception
std::cout << "Error: " << e.what() << std::endl;
}
return 0;
}
让我们分解关键组件:
throw
关键字:
std::runtime_error
try
块:
catch
块catch
块:
try
块中抛出的异常std::exception
)e.what()
获取错误消息编译并运行程序:
g++ basic_exceptions.cpp -o basic_exceptions
./basic_exceptions
示例输出:
10 / 2 = 5
Error: Division by zero is not allowed!
关于基本异常处理的关键点:
throw
用于生成异常try
和 catch
协同工作以管理异常情况在这一步骤中,你将深入探讨 C++ 异常处理的三个关键关键字:try
、catch
和 throw
。这些关键字协同工作,为你的程序创建一个健壮的错误处理机制。
打开 WebIDE,在 ~/project
目录下创建一个名为 exception_keywords.cpp
的新文件:
touch ~/project/exception_keywords.cpp
将以下代码添加到 exception_keywords.cpp
中:
#include <iostream>
#include <string>
// Function that might throw an exception
int processAge(int age) {
// Throw an exception for invalid age
if (age < 0) {
throw std::string("Age cannot be negative");
}
if (age > 120) {
throw std::string("Age is unrealistically high");
}
return age;
}
int main() {
// First try block: handling age validation
try {
// Successful case
int validAge = processAge(25);
std::cout << "Valid age: " << validAge << std::endl;
// This will throw an exception
int invalidAge1 = processAge(-5);
std::cout << "This line will not be executed" << std::endl;
}
catch (const std::string& errorMessage) {
// Catch block to handle the thrown exception
std::cout << "Error: " << errorMessage << std::endl;
}
// Second try block: another example
try {
// This will throw another exception
int invalidAge2 = processAge(150);
std::cout << "This line will also not be executed" << std::endl;
}
catch (const std::string& errorMessage) {
std::cout << "Error: " << errorMessage << std::endl;
}
return 0;
}
让我们分解关键组件:
throw
关键字:
try
块:
catch
块catch
块:
编译并运行程序:
g++ exception_keywords.cpp -o exception_keywords
./exception_keywords
示例输出:
Valid age: 25
Error: Age cannot be negative
Error: Age is unrealistically high
关于异常关键字的关键点:
throw
用于发出错误信号try
定义可能生成异常的代码块catch
处理异常并防止程序终止在这一步骤中,你将学习 C++ 中的标准异常类,以及如何使用 std::exception
层次结构来处理不同类型的运行时错误。C++ 标准库提供了一组预定义的异常类,涵盖了各种错误场景。
打开 WebIDE,在 ~/project
目录下创建一个名为 standard_exceptions.cpp
的新文件:
touch ~/project/standard_exceptions.cpp
将以下代码添加到 standard_exceptions.cpp
中:
#include <iostream>
#include <stdexcept>
#include <limits>
double divideNumbers(double numerator, double denominator) {
// Check for division by zero using std::runtime_error
if (denominator == 0) {
throw std::runtime_error("Division by zero is not allowed!");
}
return numerator / denominator;
}
void checkArrayIndex(int* arr, int size, int index) {
// Check for out-of-range access using std::out_of_range
if (index < 0 || index >= size) {
throw std::out_of_range("Array index is out of bounds!");
}
std::cout << "Value at index " << index << ": " << arr[index] << std::endl;
}
int main() {
try {
// Demonstrate division by zero exception
std::cout << "Attempting division:" << std::endl;
double result = divideNumbers(10, 0);
}
catch (const std::runtime_error& e) {
std::cout << "Runtime Error: " << e.what() << std::endl;
}
try {
// Demonstrate array index out of range exception
int numbers[] = {1, 2, 3, 4, 5};
int arraySize = 5;
std::cout << "\nAccessing array elements:" << std::endl;
checkArrayIndex(numbers, arraySize, 2); // Valid index
checkArrayIndex(numbers, arraySize, 10); // Invalid index
}
catch (const std::out_of_range& e) {
std::cout << "Out of Range Error: " << e.what() << std::endl;
}
return 0;
}
让我们探索标准异常类:
std::exception
:
what()
以获取错误描述常见的派生异常类:
std::runtime_error
:用于只能在程序执行期间检测到的运行时错误std::out_of_range
:当索引或迭代器超出有效范围时抛出std::logic_error
、std::invalid_argument
等编译并运行程序:
g++ standard_exceptions.cpp -o standard_exceptions
./standard_exceptions
示例输出:
Attempting division:
Runtime Error: Division by zero is not allowed!
Accessing array elements:
Value at index 2: 3
Out of Range Error: Array index is out of bounds!
关于标准异常类的关键点:
what()
方法返回描述性错误消息在这一步骤中,你将学习如何在 C++ 中创建自定义异常类。自定义异常允许你定义特定于应用程序需求的错误类型。
打开 WebIDE,在 ~/project
目录下创建一个名为 custom_exceptions.cpp
的新文件:
touch ~/project/custom_exceptions.cpp
将以下代码添加到 custom_exceptions.cpp
中:
#include <iostream>
#include <string>
#include <stdexcept>
// Custom exception class for bank account errors
class InsufficientFundsException : public std::runtime_error {
public:
// Constructor that takes account balance and withdrawal amount
InsufficientFundsException(double balance, double amount)
: std::runtime_error("Insufficient funds"),
currentBalance(balance),
withdrawalAmount(amount) {}
// Method to get detailed error information
double getCurrentBalance() const { return currentBalance; }
double getWithdrawalAmount() const { return withdrawalAmount; }
private:
double currentBalance;
double withdrawalAmount;
};
class BankAccount {
private:
double balance;
public:
BankAccount(double initialBalance) : balance(initialBalance) {}
void withdraw(double amount) {
// Check if withdrawal amount exceeds current balance
if (amount > balance) {
throw InsufficientFundsException(balance, amount);
}
balance -= amount;
std::cout << "Withdrawal successful. Remaining balance: $"
<< balance << std::endl;
}
double getBalance() const { return balance; }
};
int main() {
try {
// Create a bank account with initial balance
BankAccount account(100.0);
// Attempt a valid withdrawal
account.withdraw(50.0);
// Attempt an invalid withdrawal
account.withdraw(75.0);
}
catch (const InsufficientFundsException& e) {
std::cout << "Error: " << e.what() << std::endl;
std::cout << "Current Balance: $" << e.getCurrentBalance() << std::endl;
std::cout << "Attempted Withdrawal: $" << e.getWithdrawalAmount() << std::endl;
}
return 0;
}
让我们分解自定义异常类:
继承自 std::runtime_error
:
what()
方法获取错误描述自定义异常特性:
编译并运行程序:
g++ custom_exceptions.cpp -o custom_exceptions
./custom_exceptions
示例输出:
Withdrawal successful. Remaining balance: $50
Error: Insufficient funds
Current Balance: $50
Attempted Withdrawal: $75
关于自定义异常类的关键点:
在这一步骤中,你将学习如何使用不同的 catch 块处理多种异常类型。这种方法允许你为程序中可能发生的各种异常类型提供特定的错误处理。
打开 WebIDE,在 ~/project
目录下创建一个名为 multiple_catch.cpp
的新文件:
touch ~/project/multiple_catch.cpp
将以下代码添加到 multiple_catch.cpp
中:
#include <iostream>
#include <stdexcept>
#include <string>
class InvalidAgeException : public std::runtime_error {
public:
InvalidAgeException(int age)
: std::runtime_error("Invalid age"), invalidAge(age) {}
int getInvalidAge() const { return invalidAge; }
private:
int invalidAge;
};
class Student {
private:
std::string name;
int age;
public:
void setStudent(const std::string& studentName, int studentAge) {
// Validate name length
if (studentName.length() < 2) {
throw std::length_error("Name is too short");
}
// Validate age range
if (studentAge < 0 || studentAge > 120) {
throw InvalidAgeException(studentAge);
}
name = studentName;
age = studentAge;
}
void displayInfo() const {
std::cout << "Name: " << name << ", Age: " << age << std::endl;
}
};
int main() {
Student student;
// First attempt: Short name
try {
student.setStudent("A", 25);
}
catch (const std::length_error& e) {
std::cout << "Length Error: " << e.what() << std::endl;
}
catch (const InvalidAgeException& e) {
std::cout << "Age Error: " << e.what()
<< " (" << e.getInvalidAge() << ")" << std::endl;
}
// Second attempt: Invalid age
try {
student.setStudent("John Doe", 150);
}
catch (const std::length_error& e) {
std::cout << "Length Error: " << e.what() << std::endl;
}
catch (const InvalidAgeException& e) {
std::cout << "Age Error: " << e.what()
<< " (" << e.getInvalidAge() << ")" << std::endl;
}
// Successful attempt
try {
student.setStudent("Alice", 20);
student.displayInfo();
}
catch (const std::length_error& e) {
std::cout << "Length Error: " << e.what() << std::endl;
}
catch (const InvalidAgeException& e) {
std::cout << "Age Error: " << e.what()
<< " (" << e.getInvalidAge() << ")" << std::endl;
}
return 0;
}
让我们分解多个 catch 块:
多个 catch
块:
异常处理策略:
std::length_error
InvalidAgeException
编译并运行程序:
g++ multiple_catch.cpp -o multiple_catch
./multiple_catch
示例输出:
Length Error: Name is too short
Age Error: Invalid age (150)
Name: Alice, Age: 20
关于多个 catch 块的关键点:
在这一步骤中,你将学习如何使用嵌套的 try-catch 块来处理复杂的错误场景,并提供更细粒度的异常处理。嵌套的 try-catch 块允许你在代码的不同层次处理异常。
打开 WebIDE,在 ~/project
目录下创建一个名为 nested_exceptions.cpp
的新文件:
touch ~/project/nested_exceptions.cpp
将以下代码添加到 nested_exceptions.cpp
中:
#include <iostream>
#include <stdexcept>
#include <string>
class FileReadError : public std::runtime_error {
public:
FileReadError(const std::string& filename)
: std::runtime_error("Error reading file"), fileName(filename) {}
std::string getFileName() const { return fileName; }
private:
std::string fileName;
};
class DataProcessor {
public:
void processFile(const std::string& filename) {
try {
// Simulate file reading
if (filename.empty()) {
throw FileReadError("Empty filename");
}
std::cout << "Reading file: " << filename << std::endl;
try {
// Simulate data processing
validateData(filename);
}
catch (const std::runtime_error& e) {
std::cout << "Inner try-catch: Data validation error" << std::endl;
std::cout << "Error details: " << e.what() << std::endl;
// Rethrow the exception to outer catch block
throw;
}
}
catch (const FileReadError& e) {
std::cout << "Outer try-catch: File read error" << std::endl;
std::cout << "Filename: " << e.getFileName() << std::endl;
}
catch (...) {
std::cout << "Caught unknown exception" << std::endl;
}
}
private:
void validateData(const std::string& filename) {
// Simulate data validation
if (filename == "corrupt.txt") {
throw std::runtime_error("Corrupt file data");
}
std::cout << "Data validation successful" << std::endl;
}
};
int main() {
DataProcessor processor;
// Scenario 1: Empty filename
std::cout << "Scenario 1: Empty Filename" << std::endl;
processor.processFile("");
// Scenario 2: Corrupt file
std::cout << "\nScenario 2: Corrupt File" << std::endl;
processor.processFile("corrupt.txt");
// Scenario 3: Valid file
std::cout << "\nScenario 3: Valid File" << std::endl;
processor.processFile("data.txt");
return 0;
}
让我们分解嵌套的 try-catch 块:
外层 try-catch 块:
FileReadError
和其他潜在错误内层 try-catch 块:
捕获所有异常的处理器 (catch (...)
):
编译并运行程序:
g++ nested_exceptions.cpp -o nested_exceptions
./nested_exceptions
示例输出:
Scenario 1: Empty Filename
Outer try-catch: File read error
Filename: Empty filename
Scenario 2: Corrupt File
Reading file: corrupt.txt
Inner try-catch: Data validation error
Error details: Corrupt file data
Scenario 3: Valid File
Reading file: data.txt
Data validation successful
关于嵌套 try-catch 块的关键点:
在本实验中,你学习了 C++ 中异常处理的基本概念。你从理解如何使用 throw
、try
和 catch
关键字抛出和捕获基本异常开始。你探索了使用 std::runtime_error
异常类来处理除以零错误。此外,你还学习了如何在 catch
块中使用 e.what()
函数访问错误消息。这些技术提供了一种优雅处理运行时错误并防止程序崩溃的方式,使你能够编写更健壮和可靠的 C++ 应用程序。