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 fromstd::exception
and overrides thewhat
method to return a custom error message. - In the
main
function, aMyException
object is thrown and caught by thecatch
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
andInvalidDepositException
classes inherit fromstd::exception
and override thewhat
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 anOverdraftException
to be thrown and caught by the correspondingcatch
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 anInvalidAccountInitialization
exception if the initial balance is negative. - The
main
function attempts to initialize an account with a negative balance, which causes anInvalidAccountInitialization
exception to be thrown and caught by the correspondingcatch
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.