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
¶ Δ 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.
You can override virtual functions defined in a base class from the Visual Studio Properties window.
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With