Custom Exception Classes
In addition to the standard exception classes provided by the C++ Standard Library, you can define your own custom exception classes to handle specific error conditions in your application. Creating custom exceptions allows you to provide more meaningful error messages and handle specific types of errors more precisely.
1. Defining a Custom Exception Class
A custom exception class in C++ is usually derived from the std::exception class or any of its derived classes, like std::runtime_error. This allows your custom exception to integrate smoothly with the C++ exception handling mechanism.
Here’s a basic example of how to define a custom exception class:
#include<iostream>#include <exception>classMyCustomException : public std::exception {
private:
constchar* message;
public:
MyCustomException(constchar* msg) : message(msg) {}
// Override the what() method from std::exceptionconst char* what() const noexcept override {
return message;
}
};
Explanation:
- Inheritance: MyCustomException is derived from std::exception.
- Constructor: It takes a const char* as a message to describe the exception.
- what() Method: The what() method is overridden to return the exception message.
2. Throwing and Catching a Custom Exception
Once you’ve defined your custom exception class, you can throw it just like any other exception and catch it using a catch block.
Here’s an example:
intmain(){
try {
throwMyCustomException("Something went wrong!");
} catch (const MyCustomException& e) {
std::cerr << "Caught MyCustomException: " << e.what() << std::endl;
}
return0;
}
Explanation:
- Throwing: The throw statement is used to throw an instance of MyCustomException with a custom error message.
- Catching: The catch block catches the exception and accesses the error message using the what() method.
3. Custom Exception with More Information
You can make your custom exception class more informative by including additional data, such as an error code, file name, or line number.
Here’s an example of a more detailed custom exception class:
#include<iostream>#include <exception>#include <string>classDetailedException : public std::exception {
private:
std::string message;
int errorCode;
public:
DetailedException(const std::string& msg, int code)
: message(msg), errorCode(code) {}
constchar* what()constnoexceptoverride{
return message.c_str();
}
intgetErrorCode()constnoexcept{
return errorCode;
}
};
intmain(){
try {
throwDetailedException("An error occurred", 404);
} catch (const DetailedException& e) {
std::cerr << "Caught DetailedException: " << e.what() << std::endl;
std::cerr << "Error Code: " << e.getErrorCode() << std::endl;
}
return0;
}
Explanation:
- Additional Information: DetailedException stores both an error message and an error code.
- getErrorCode() Method: This method provides access to the error code, allowing for more detailed error handling.
4. Best Practices for Custom Exception Classes
Derive from std::exception: By inheriting from std::exception or one of its derived classes, you ensure that your custom exception is compatible with standard exception handling mechanisms.
Override the what() Method: Always override the what() method to provide a meaningful description of the error. This helps in debugging and understanding the nature of the exception.
Use Exception Objects: When throwing exceptions, throw objects of your custom exception class rather than pointers to these objects. This ensures proper memory management.
Consider Adding Context: Consider adding more context to your exceptions, such as error codes, filenames, line numbers, or other relevant information that can help in diagnosing the problem.
5. Example: Using Custom Exceptions in a Function
Here’s an example that demonstrates how to use a custom exception in a function:
#include<iostream>#include <exception>classDivisionByZeroException : public std::exception {
private:
constchar* message;
public:
DivisionByZeroException() : message("Division by zero is not allowed!") {}
constchar* what()constnoexceptoverride{
return message;
}
};
doubledivide(double a, double b){
if (b == 0) {
throwDivisionByZeroException();
}
return a / b;
}
intmain(){
try {
double result = divide(10, 0);
std::cout << "Result: " << result << std::endl;
} catch (const DivisionByZeroException& e) {
std::cerr << "Caught Exception: " << e.what() << std::endl;
}
return0;
}
Explanation:
- Custom Exception: DivisionByZeroException is thrown when an attempt is made to divide by zero.
- Function Usage: The divide function checks for a zero divisor and throws the custom exception if necessary.
- Error Handling: The main function catches the exception and prints the error message.
Summary
Custom exception classes in C++ allow you to create tailored error-handling mechanisms specific to your application’s needs. By deriving from std::exception and overriding the what() method, you can provide meaningful error messages and handle complex error scenarios effectively.