OOPにおける例外処理
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 81/104。
C++におけるException handlingは、実行時エラーを検出して対応するための構造化された方法を提供します。オブジェクト指向プログラミングでは、exceptionsはclass階層と自然に統合されるため、何が問題だったのかに関するコンテキストを持つ、意味のあるエラー型を作成できます。
基本的な仕組みでは、try、throw、catchという3つのキーワードを使用します。失敗する可能性のあるコードは try ブロックに記述し、エラーは throw で通知し、catch ブロックで特定の例外型を処理します。
#include <iostream>
#include <stdexcept>
class BankAccount {
double balance;
public:
BankAccount(double b) : balance(b) {}
void withdraw(double amount) {
if (amount > balance) {
throw std::runtime_error("Insufficient funds");
}
balance -= amount;
}
double getBalance() const { return balance; }
};
int main() {
BankAccount account(100.0);
try {
account.withdraw(150.0);
} catch (const std::runtime_error& e) {
std::cout << "Error: " << e.what() << "\n";
}
std::cout << "Balance: " << account.getBalance() << "\n";
}C++標準ライブラリは、std::exceptionを基底とする例外クラスの階層を提供します。一般的な派生クラスには、実行時の問題に使用するstd::runtime_errorや、プログラミング上の誤りに使用するstd::logic_errorがあります。すべての標準例外は、エラーメッセージを返すwhat()メソッドを提供します。
exception がスローされると、スタックがアンワインドされます。プログラムが一致する catch block を探す間、すべてのローカルオブジェクトに対してデストラクタが呼び出されます。これにより、エラーが発生した場合でも適切なクリーンアップが保証されるため、RAII と exception 処理は非常にうまく連携します。
チャレンジ
簡単オブジェクト指向のコンテキストで例外処理を実演する、安全な除算 Calculator を作成しましょう。除算操作を実行し、問題が発生したときに意味のある例外をスローする Calculator class を作成し、その後、main プログラムでそれらの例外を適切に処理します。
コードを3つのファイルに分けて整理します。
Calculator.h:適切なエラー処理を使用して数学演算を実行するCalculatorclass を Define します。Calculatorには、除算の結果を返すdivide(double numerator, double denominator)method が必要です。ただし、denominator がゼロの場合は、messageDivision by zeroとともにstd::runtime_errorをスローする必要があります。numerator または denominator の either が負の場合は、messageNegative values not allowedとともにstd::invalid_argumentをスローする必要があります。また、値の平方根を返す
safeSqrt(double value)method も include します。値が負の場合は、messageCannot compute square root of negative numberとともにstd::runtime_errorをスローします。sqrtfunction のために<cmath>を include する必要があります。Calculator.cpp:ヘッダーファイルで宣言した methods を Implement します。必要なヘッダー(<stdexcept>と<cmath>)を include し、演算を実行する前に条件を確認してください。main.cpp:3つの inputs を読み取ります(それぞれ別の行に入力します)。- 操作の種類:
divideまたはsqrtの either - 1つ目の number(double)
- 2つ目の number(double):除算の場合のみ使用し、sqrt の場合は無視されます
Calculatorobject を Create し、try block 内で要求された操作を実行します。操作が成功した場合は、Result: [value]を print します。exception が catch された場合は、exception のwhat()method から取得した message を使用してError: [message]を print します。try-catch block の後(exception が発生したかどうかに関係なく)、
Calculation completeを print して、例外を処理した後もプログラムが実行を続けることを示します。- 操作の種類:
たとえば、inputs が divide、10、2 の場合:
Result: 5
Calculation completeinputs が divide、10、0 の場合:
Error: Division by zero
Calculation completeinputs が divide、-5、2 の場合:
Error: Negative values not allowed
Calculation completeinputs が sqrt、16、0 の場合:
Result: 4
Calculation completeinputs が sqrt、-9、0 の場合:
Error: Cannot compute square root of negative number
Calculation completeプログラムが exception を catch して意味のある message を表示し、その後も実行を続けることで、エラーを適切に処理していることに注目してください。このパターンにより、エラー処理を簡潔に保ち、main logic を happy path に集中させることができます。
自分で試してみよう
#include <iostream>
#include <string>
#include "Calculator.h"
using namespace std;
int main() {
// 入力を読み取る
string operation;
double num1, num2;
cin >> operation;
cin >> num1;
cin >> num2;
// Calculatorオブジェクトを作成する
Calculator calc;
// TODO: try-catchブロックを使用して演算を実行する
// - operationが"divide"の場合、calc.divide(num1, num2)を呼び出す
// - operationが"sqrt"の場合、calc.safeSqrt(num1)を呼び出す
// - 成功時は"Result: "に続いて結果を出力する
// - 例外をキャッチして"Error: "に続いて例外メッセージを出力する(what()を使用)
// - After the try-catch, always print "Calculation complete"
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタパラメータ付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ徹底解説Rule of Three / Five / Zero復習 - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () の演算子オーバーロード型変換演算子復習 - Matrixクラス自分で練習してみよう: C++オンラインコンパイラ