Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception specification when overriding a virtual function

Consider the following code:


class A
{
public:
    virtual void f() throw ( int ) { }
};

class B: public A
{
public:
    void f() throw ( int, double ) { }
};

When compiled, it says that derived class B has a looser throw specifier compared to A. What is the importance of this? If we try to exchange their exception specification, such that A::f() throws int and double while B::f() throws only int, the error does not appear.

like image 630
jasonline Avatar asked Mar 05 '10 15:03

jasonline


People also ask

Can you override a virtual function?

You can override virtual functions defined in a base class from the Visual Studio Properties window.

Do I need to override virtual functions?

It is not mandatory for the derived class to override (or re-define the virtual function), in that case, the base class version of the function is used. A class may have virtual destructor but it cannot have a virtual constructor.

What if virtual function is not overridden?

In addition, if you do not override a virtual member function in a derived class, a call to that function uses the function implementation defined in the base class. A function that has a deleted definition cannot override a function that does not have a deleted definition.


2 Answers

  1. Don't use exception specifications in C++. It's very counter-intuitive compared to, say, Java's ones.
  2. Having a wider specification in the derived class breaks LSP (Liskov Substitution Principle).

To expand on point 2: A's callers expect that only int comes out, but if you use a B (which, because it's publicly derived from A, also means it's usable as an A), suddenly double can come out too, and that would break A's contract (that only int gets thrown).

like image 162
Chris Jester-Young Avatar answered Oct 01 '22 05:10

Chris Jester-Young


Your B violates the Liskov Substitution Principle - eg:

void foo(A* a) throw() // ie I will not throw
{
  try
  {
     a->f();
  }
  catch(int)
  {}
}

This is valid according to the interface for A; in particular, we do not expect a double to be thrown. But consider if we were to call

foo(new B)

with the interface you describe, and

B::f()
were to throw a double.
like image 29
tragomaskhalos Avatar answered Oct 01 '22 04:10

tragomaskhalos