Menu
Coddy logo textTech

OOPにおける例外処理

CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 81/104。

C++におけるException handlingは、実行時エラーを検出して対応するための構造化された方法を提供します。オブジェクト指向プログラミングでは、exceptionsはclass階層と自然に統合されるため、何が問題だったのかに関するコンテキストを持つ、意味のあるエラー型を作成できます。

基本的な仕組みでは、trythrowcatchという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 処理は非常にうまく連携します。

challenge icon

チャレンジ

簡単

オブジェクト指向のコンテキストで例外処理を実演する、安全な除算 Calculator を作成しましょう。除算操作を実行し、問題が発生したときに意味のある例外をスローする Calculator class を作成し、その後、main プログラムでそれらの例外を適切に処理します。

コードを3つのファイルに分けて整理します。

  • Calculator.h:適切なエラー処理を使用して数学演算を実行する Calculator class を Define します。

    Calculator には、除算の結果を返す divide(double numerator, double denominator) method が必要です。ただし、denominator がゼロの場合は、message Division by zero とともに std::runtime_error をスローする必要があります。numerator または denominator の either が負の場合は、message Negative values not allowed とともに std::invalid_argument をスローする必要があります。

    また、値の平方根を返す safeSqrt(double value) method も include します。値が負の場合は、message Cannot compute square root of negative number とともに std::runtime_error をスローします。sqrt function のために <cmath> を include する必要があります。

  • Calculator.cpp:ヘッダーファイルで宣言した methods を Implement します。必要なヘッダー(<stdexcept><cmath>)を include し、演算を実行する前に条件を確認してください。
  • main.cpp:3つの inputs を読み取ります(それぞれ別の行に入力します)。
    1. 操作の種類:divide または sqrt の either
    2. 1つ目の number(double)
    3. 2つ目の number(double):除算の場合のみ使用し、sqrt の場合は無視されます

    Calculator object を Create し、try block 内で要求された操作を実行します。操作が成功した場合は、Result: [value] を print します。exception が catch された場合は、exception の what() method から取得した message を使用して Error: [message] を print します。

    try-catch block の後(exception が発生したかどうかに関係なく)、Calculation complete を print して、例外を処理した後もプログラムが実行を続けることを示します。

たとえば、inputs が divide102 の場合:

Result: 5
Calculation complete

inputs が divide100 の場合:

Error: Division by zero
Calculation complete

inputs が divide-52 の場合:

Error: Negative values not allowed
Calculation complete

inputs が sqrt160 の場合:

Result: 4
Calculation complete

inputs が sqrt-90 の場合:

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;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: C++オンラインコンパイラ