Suppose class Base has member function f() that promises to throw only objects of class X. If class Derived overrides f() and throws an object of unrelated class Y, user code will break, because users will get an unexpected exception. However, Derived::f() can throw an X2 if X2 is derived from X due to the is-a conversion that allows a derived class reference to automatically be converted to a base class reference. #include <cstdlib> #include <iostream> using namespace std; class X { }; class Y { }; class X2 : public X { }; class Base { public: virtual void f() throw(X); //PROMISE: may throw 'X', but never throws anything else virtual ~Base() throw(); }; Base::~Base() throw() { } void userCode(Base& base) throw() { try { base.f(); cout << "OK: base.f() didn't throw anything\n"; } catch (X& x) { cout << "OK: base.f() threw an X\n"; } catch (...) { cout << "huh? base.f() threw something other than X!\n"; } } class Derived : public Base { public: virtual void f() throw(X, X2, Y); //PROMISE: // may throw X <-- 1 // may throw X2 <-- 2 // may throw Y <-- 3 }; void Base::f() throw(X) { if (rand() % 2 == 0) throw X(); } void Derived::f() throw(X, X2, Y) { int r = rand() % 4; if (r == 0) throw X(); <-- 4 if (r == 1) throw X2(); <-- 5 if (r == 2) throw Y(); <-- 6 } int main() { Base b; Derived d; cout << "using 'Base'\n"; for (int i = 0; i < 10; ++i) userCode(b); cout << "using 'Derived'\n"; for (int j = 0; j < 10; ++j) userCode(d); }
The overridden member function in the derived class has a weaker promise than that made by the base class: Base promised not to throw a Y, and Derived broke this promise. Weakening a promise breaks user code. |