Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Exception throw annotations on virtual functions

Tags:

c++

throw

virtual

I saw the following snippet code:

class Foo
{
public:
        void virtual func() throw (int, float) = 0;
};

class Bar : public Foo
{
public:
        void virtual func() throw(short);      // line 1: compile error "
                                                                      // looser throw specifier"
        void virtual func() throw();                // line 2: can compile
        void virtual func() throw(float, int); // line 3: can compile
        void virtual func() throw(float);        // line 4: can compile
        void virtual func() throw(int);           // line 5: can compile

};

int main(void)
{
        return 1;
}

Q1> What is meaning of

void virtual func() throw (int, float) = 0;

Q2> why line1 cannot pass the compiler?

Thank you

like image 685
q0987 Avatar asked Sep 21 '10 18:09

q0987


People also ask

Do virtual functions need to be overriden?

¶ Δ A pure virtual function is a function that must be overridden in a derived class and need not be defined. A virtual function is declared to be “pure” using the curious =0 syntax.

Can you override a virtual function?

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

Do virtual functions prevent instantiation?

Declaring a method as pure virtual means that classes that inherit your class will have to implement that method or leave it pure virtual, in which case the derived class will also be an abstract class that cannot be instantiated.

Does C support virtual function?

You get the same runtime performance as a C++ member function call, but without any compile-time checking to enforce access control. In C, virtual function calls look unlike any other kind of function call.


3 Answers

Let's break this down. The declaration:

void virtual func() throw (int, float) = 0;

has 2 constructs that you're asking about. the =0 construct tells the compiler that the declared function is 'abstract', which tells the compiler that the function need not be defined in the class Foo (though it can be - but it usually isn't) and that an object of class Foo cannot be directly created - either as a local, global or via new. However, you can have pointers or references to objects of class Foo. Some derived class needs to override the function as a non-abstract function - objects of that class can be directly created (as long as there are no other abstract functions that haven't been made 'concrete').

The throw (int, float) construct is an exception specifification. This tells the compiler that the function's contract is that it will only throw exceptions of type int or float if it throws an exception. If the function throws some other kind of exception, the compiler is obligated to handle that specially (by calling std::unexpected()).

Now, if you try to override that function in a derived class with the following declaration:

void virtual func() throw(short);

You're saying that the function's contract is that it will throw exceptions of type short if an exception is thrown. However, throwing short is not part of the contract of the function being overridden, so the compiler doesn't permit it.

If you declare the override like so:

void virtual func() throw(float);

You're saying that the override can throw a float, which is part of the contract of the original declaration (if it never throws an int that doesn't break the contract - the original contract only says that the function is allowed to throw an int, not that it has to).

The relevant part of the standard is 15.4/3 Exception specifications:

If a virtual function has an exception-specification, all declarations, including the definition, of any function that overrides that virtual function in any derived class shall only allow exceptions that are allowed by the exception-specification of the base class virtual function.

Note that the standard explicitly states that an exception specification is not part of the function's type (15.4/12), so a function pointer can, for example, point to functions that have different exception specifications.

like image 79
Michael Burr Avatar answered Sep 19 '22 13:09

Michael Burr


You're defining the same function signature many times. The different throw() qualifiers are not enough to disambiguate the functions.

The throw() qualifier simply means that the specified function is only expected to throw the types listed in the parenthesis following the qualifier. However, this does not actually prevent the function from throwing. Rather, if the function actually does throw any unlisted types, your program will terminate.

like image 28
Charles Salvia Avatar answered Sep 22 '22 13:09

Charles Salvia


The function you're defining in the base class is making a guarantee - it can only throw an int or a float. Your line 1 is failing because it's breaking the guarantee by saying it will throw a short, which isn't either of the above.

The = 0 in Q1 declares that each derived class that you try to create an instance of will need to provide its own declaration and implementation of this function. The base class may also provide an implementation, but typically it doesn't.

like image 23
Mark Ransom Avatar answered Sep 21 '22 13:09

Mark Ransom