9.2 Custom Exceptions
Built-in exceptions handle many general errors, but real projects often have business-rule failures. "Out of stock" is not a C++ syntax error or a type error; it is a violated business rule.
Defining an Exception Class
Custom exceptions often inherit from std::runtime_error or another standard exception type. In C++, a custom class usually passes its message to the parent constructor with std::runtime_error(message).
#include <stdexcept>
#include <string>
class OutOfStockException : public std::runtime_error {
public:
explicit OutOfStockException(const std::string& message)
: std::runtime_error(message) {
}
};The message can be passed when throwing it:
throw OutOfStockException("Notebook is out of stock.");The exception name should clearly express the error. OutOfStockException is more specific and easier for callers to recognize than a generic std::exception.
Stock Example
#include <iostream>
#include <stdexcept>
#include <string>
class OutOfStockException : public std::runtime_error {
public:
explicit OutOfStockException(const std::string& message)
: std::runtime_error(message) {
}
};
class Product {
public:
std::string name;
int stock;
Product(std::string name, int stock) : name(name), stock(stock) {
}
void purchase(int quantity) {
if (quantity <= 0) {
throw std::invalid_argument("Quantity must be greater than 0.");
}
if (quantity > stock) {
throw OutOfStockException(name + " is out of stock.");
}
stock -= quantity;
}
};
int main() {
Product product("Notebook", 5);
try {
product.purchase(3);
std::cout << "Purchase succeeded. Remaining stock: " << product.stock << std::endl;
product.purchase(4);
} catch (const OutOfStockException& error) {
std::cout << "Purchase failed: " << error.what() << std::endl;
}
return 0;
}Output:
Purchase succeeded. Remaining stock: 2
Purchase failed: Notebook is out of stock.In this example, std::invalid_argument means the argument itself is unreasonable, while OutOfStockException means a business rule blocks the purchase. Different exceptions express different problems, so caller code can respond more accurately.
Why Custom Exceptions Matter
The value of custom exceptions is not merely that they can throw errors. They give errors semantics.
When caller code catches OutOfStockException, it knows the problem is stock-related and can show business actions such as restocking or choosing another product. When it catches std::invalid_argument, it is more likely to ask the user to change the quantity.