C++ User-Defined Exceptions

Introduction

In C++, user-defined exceptions allow you to create custom exception classes tailored to your specific error-handling needs. By defining your own exception classes, you can provide more detailed and meaningful error messages and handle exceptions more effectively in your application.

Creating User-Defined Exception Classes

User-defined exception classes are typically derived from the standard std::exception class or one of its derived classes. You can override the what method to return a custom error message.

Example: Basic User-Defined Exception

Let’s create a simple user-defined exception class called MyException.

#include <iostream>
#include <exception>
using namespace std;

// Custom exception class
class MyException : public exception {
public:
    // Override the what() method to return a custom error message
    const char* what() const noexcept override {
        return "My custom exception occurred";
    }
};

int main() {
    try {
        // Throw a custom exception
        throw MyException();
    } catch (const MyException& e) {
        // Catch and handle the custom exception
        cout << "Exception: " << e.what() << endl;
    }

    return 0;
}

Output

Exception: My custom exception occurred

Explanation

  • The MyException class inherits from std::exception and overrides the what method to return a custom error message.
  • In the main function, a MyException object is thrown and caught by the catch block, which prints the custom error message.

Practical Example: Bank Account Exception

Let’s create a more practical example where we define custom exceptions for a bank account system. We’ll create custom exceptions for handling invalid account operations like overdraft and invalid deposit amounts.

Custom Exception Classes

#include <iostream>
#include <exception>
using namespace std;

// Custom exception class for overdraft
class OverdraftException : public exception {
public:
    const char* what() const noexcept override {
        return "Overdraft: Insufficient funds for withdrawal";
    }
};

// Custom exception class for invalid deposit
class InvalidDepositException : public exception {
public:
    const char* what() const noexcept override {
        return "Invalid deposit: Amount must be positive";
    }
};

Bank Account Class

class BankAccount {
private:
    double balance;

public:
    // Constructor to initialize balance
    BankAccount(double initialBalance) : balance(initialBalance) {}

    // Method to deposit money
    void deposit(double amount) {
        if (amount <= 0) {
            throw InvalidDepositException();
        }
        balance += amount;
    }

    // Method to withdraw money
    void withdraw(double amount) {
        if (amount > balance) {
            throw OverdraftException();
        }
        balance -= amount;
    }

    // Method to check the balance
    double getBalance() const {
        return balance;
    }
};

Main Function

int main() {
    try {
        BankAccount account(100.0); // Initialize account with $100

        // Deposit money
        account.deposit(50.0);
        cout << "Balance after deposit: $" << account.getBalance() << endl;

        // Withdraw money
        account.withdraw(200.0); // This will cause an overdraft exception
    } catch (const OverdraftException& e) {
        cout << "Exception: " << e.what() << endl;
    } catch (const InvalidDepositException& e) {
        cout << "Exception: " << e.what() << endl;
    } catch (const exception& e) {
        cout << "Exception: " << e.what() << endl;
    }

    return 0;
}

Output

Balance after deposit: $150
Exception: Overdraft: Insufficient funds for withdrawal

Explanation

  • The OverdraftException and InvalidDepositException classes inherit from std::exception and override the what method to return custom error messages.
  • The BankAccount class has methods for depositing and withdrawing money. If an invalid operation is attempted (like a negative deposit or an overdraft), a custom exception is thrown.
  • In the main function, we try to deposit and withdraw money. The deposit is successful, but the withdrawal causes an OverdraftException to be thrown and caught by the corresponding catch block, which prints the error message.

Advanced Example: Handling Multiple Exceptions

Let’s extend the previous example to handle multiple types of exceptions in different scenarios.

Additional Custom Exception

// Custom exception class for invalid account initialization
class InvalidAccountInitialization : public exception {
public:
    const char* what() const noexcept override {
        return "Invalid account initialization: Initial balance must be non-negative";
    }
};

Updated Bank Account Class

class BankAccount {
private:
    double balance;

public:
    // Constructor to initialize balance
    BankAccount(double initialBalance) {
        if (initialBalance < 0) {
            throw InvalidAccountInitialization();
        }
        balance = initialBalance;
    }

    // Method to deposit money
    void deposit(double amount) {
        if (amount <= 0) {
            throw InvalidDepositException();
        }
        balance += amount;
    }

    // Method to withdraw money
    void withdraw(double amount) {
        if (amount > balance) {
            throw OverdraftException();
        }
        balance -= amount;
    }

    // Method to check the balance
    double getBalance() const {
        return balance;
    }
};

Updated Main Function

int main() {
    try {
        BankAccount account(-100.0); // This will cause an invalid account initialization exception

        // Deposit money
        account.deposit(50.0);
        cout << "Balance after deposit: $" << account.getBalance() << endl;

        // Withdraw money
        account.withdraw(200.0); // This will cause an overdraft exception
    } catch (const InvalidAccountInitialization& e) {
        cout << "Exception: " << e.what() << endl;
    } catch (const OverdraftException& e) {
        cout << "Exception: " << e.what() << endl;
    } catch (const InvalidDepositException& e) {
        cout << "Exception: " << e.what() << endl;
    } catch (const exception& e) {
        cout << "Exception: " << e.what() << endl;
    }

    return 0;
}

Output

Exception: Invalid account initialization: Initial balance must be non-negative

Explanation

  • The InvalidAccountInitialization class is added to handle exceptions related to invalid initial balance.
  • The BankAccount constructor now throws an InvalidAccountInitialization exception if the initial balance is negative.
  • The main function attempts to initialize an account with a negative balance, which causes an InvalidAccountInitialization exception to be thrown and caught by the corresponding catch block.

Conclusion

User-defined exceptions in C++ allow you to create custom error-handling mechanisms tailored to your application’s specific needs. By defining custom exception classes, you can provide detailed error messages and handle different error scenarios effectively. Understanding and using user-defined exceptions is essential for writing robust and maintainable C++ programs.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top