exception specification of overriding function is more lax than base version - c++

I want to custom an Exception class, here's the code:
class TestException : std::exception{
public:
const char *what() const override {
return "TestException";
}
};
I used Clion and the IDE give me a warning on the function what():exception specification of overriding function is more lax than base version
But if I build the code with gcc, there's no warning came out.
I used c++ 14, gcc 6.5.0
Can anybody help to explain what does the warning mean and can I just ignore it?

what from std::exception is a virtual function and a virtual function in a derived class cannot have a laxer exception specification than the function it overrides in the base class.
This is mentioned in the section on "Exception specifications" in the standard.
18.4 Exception specifications [except.spec]
...
4. If a virtual function has a non-throwing exception specification, all declarations, including the definition, of any function that overrides that virtual function in any derived class shall have a non-throwing exception specification, unless the overriding function is defined as deleted.
And the example given (which is somewhat similar to the code in the question) illustrates this as well.
struct B
{
virtual void f() noexcept;
virtual void g();
virtual void h() noexcept = delete;
};
struct D: B
{
void f(); // ill-formed
void g() noexcept; // OK
void h() = delete; // OK
};
The declaration of D::f is ill-formed because it has a potentially-throwing exception specification, whereas B::f has a non-throwing exception specification.
The solution is to change your code like:
class TestException : std::exception{
public:
const char *what() const noexcept override {
return "TestException";
}
};
See compilation here.

what member function of std::exception is declared as noexcept since C++11. You should therefore make your overridden what noexcept as well. (Actually, this is what the error message says.)
Note that the noexcept keyword must come before the override keyword (see, e.g., The order of override and noexcept in the standard for details).

The warning you are facing is related to the fact that you are using C++14, if you would compile with C++17 this becomes an error. Hence I would not recommend ignoring it.
Whats going on?
std::exception defines the method what as: virtual const char* what() const noexcept;. You inherit from this method and you re-implement it without specifying noexcept. By result, you are telling that your implementation can throw exceptions, while the base method indicates this should never throw. (And callers will assume so)
This was fixed in C++17, which made noexcept part of the type system, and requires you to fix this code:
const char *what() const noexcept override

Related

Implicitly virtual constexpr function

Virtual functions cannot be constexpr however, when a function is implicitly virtual through inheritance, the compilers I have tried don't complain about it.
Here is a sample code:
class A
{
virtual void doSomething() {}
};
class B : public A
{
constexpr void doSomething() override {} // implicitly virtual constexpr
// but no compilation error
};
class C : public A
{
virtual constexpr void doSomething() override {} // explicitly virtual constexpr
// compilation error
};
I tried it with gcc 7.2.0 and clang 5.0.0.
Are those compilers not compliant to the standard in this regard, or are implicitly virtual constexpr functions allowed ?
The compilers have a bug. Note that this has been fixed in clang 3.5 already, not sure why you don't get an error, because I do.
The standard is pretty explicit about this in [dcl.constexpr]p3:
The definition of a constexpr function shall satisfy the following requirements:
it shall not be virtual;
[...]
It does't matter whether doSomething is implicitly virtual or not. In both cases, it is considered to be virtual, and so it violates the point above.

Same member function of a class can be declared with "override & final" specifier in c++?

override and final specifier has been introduced in C++11.The below program uses these specifier as follows:
#include<iostream>
template<typename T>
void display(const T& val) { std::cout<<val<<"\n"; }
class Shape {
public:
virtual ~Shape()= default;
virtual void Draw() { display("Shape::Draw()");}
virtual void DisplayName() { display("Shape");}
};
class Circle : public Shape {
public:
virtual ~Circle() = default;
virtual void Draw() override final { display("Circle::Draw()");}
virtual void DisplayName() override { display("Cicle");}
};
int main()
{
}
In the above sample program Circle::Draw() has been defined as override final specifier. This compiles successfully however if the same method is defined as final override, then it throws an compile time error.
Wanted to understand the use cases of override and final specifier for the same method for a class?. When we should use it in our program?
In my opinion it is a compiler bug. At least at www.ideone com the code is compiled successfully.
Acoording to the C++ Standard (10.3 Virtual functions)
4 If a virtual function f in some class B is marked with the
virt-specifier final and in a class D derived from B a function
D::f overrides B::f, the program is ill-formed.
[ Example:
struct B {
virtual void f() const final;
};
struct D : B {
void f() const; // error: D::f attempts to override final B::f
};
—end example ]
A class may not be a derived class of itself. So the code you showed shall be compiled.
Also
5 If a virtual function is marked with the virt-specifier override and
does not override a member function of a base class, the program is
ill-formed.
[ Example:
struct B {
virtual void f(int);
};
struct D : B {
virtual void f(long) override; // error: wrong signature overriding B::f
virtual void f(int) override; // OK
};
—end example ]
In your example function Draw of class Circle is marked with virt-specidier override and indeed overrides the function of the base class.
This is a compiler bug. According to the grammar that the C++11 standard is specifying in [class.mem]:
member-declarator: declarator
virt-specifier-seqopt pure-specifieropt
declarator
brace-or-equal-initializeropt
identifieropt
attribute-specifier-seqopt : constant-expression
virt-specifier-seq:
virt-specifier
virt-specifier-seq
virt-specifier virt-specifier:
override
final
The virt-specifier-seq doesn't imply any order in the virt-specifiers in the declaration.
When we should use it in our program?
This question might be worth looking at.
It looks like Vlad from Moscow is correct
From the override specifier at cppreference.com:
declarator virt-specifier-seq(optional) function-body
In both cases, virt-specifier-seq, if used, is either override or final, or final override or override final.
And again for the final specifier at cppreference.com:
declarator virt-specifier-seq(optional) function-body
virt-specifier-seq, if used, is either override or final, or final override or override final.
Compiler bugs aside, I would encourage you to pick an order and stick to it consistently - don't mix and match the word order through your codebase.

c++ overloaded virtual function warning by clang?

clang emits a warning when compiling the following code:
struct Base
{
virtual void * get(char* e);
// virtual void * get(char* e, int index);
};
struct Derived: public Base {
virtual void * get(char* e, int index);
};
The warning is:
warning: 'Derived::get' hides overloaded virtual function [-Woverloaded-virtual]
(the said warning needs to be enabled of course).
I don't understand why. Note that uncommenting the same declaration in Base shuts the warning up. My understanding is that since the two get() functions have different signatures, there can be no hiding.
Is clang right? Why?
Note this is on MacOS X, running a recent version of Xcode.
clang --version
Apple LLVM version 5.0 (clang-500.1.74) (based on LLVM 3.3svn)
Update: same behavior with Xcode 4.6.3.
This warning is there to prevent accidental hiding of overloads when overriding is intended. Consider a slightly different example:
struct chart; // let's pretend this exists
struct Base
{
virtual void* get(char* e);
};
struct Derived: public Base {
virtual void* get(chart* e); // typo, we wanted to override the same function
};
As it is a warning, it doesn't necessarily mean it is a mistake, but it might indicate one. Usually such warnings have a means of shutting them off by being more explicit and letting the compiler know you did intend what you wrote. I believe in this case you can do the following:
struct Derived: public Base {
using Base::get; // tell the compiler we want both the get from Base and ours
virtual void * get(char* e, int index);
};
Another way of disabling the warning keeping the struct public interface intact would be:
struct Derived: public Base
{
virtual void * get(char* e, int index);
private:
using Base::get;
};
This disallows a consumer of Derived to call Derived::get(char* e) while silencing the warning:
Derived der;
der.get("", 0); //Allowed
der.get(""); //Compilation error
R. Martinho Fernandes solution's is perfectly valid if you actually want to bring the get() method taking a single char* argument into Derived scope.
Actually, in the snippet you provided, there is no need for virtual methods (since Base and Derived do not share any method with the same signature).
Assuming there is actually a need for polymorphism, the hiding behavior could nonetheless be what is intended.
In this case, it is possible to locally disable Clang's warning, with the following pragma :
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverloaded-virtual"
// Member declaration raising the warning.
#pragma clang diagnostic pop
Warning means, that there will be no
void * get(char* e)
function in the scope of Derived class, cause it hidden by another method with same name.
Compiler won't search for function in base classes if derived class has at least one method with specified name, even if it has another arguments.
This sample code won't compile:
class A
{
public:
virtual void Foo() {}
};
class B : public A
{
public:
virtual void Foo(int a) {}
};
int main()
{
B b;
b.Foo();
return 0;
}

What the c++ standard says about loosing throw specifier in default destructor

Three different compilers show three different behaviours compiling this code:
class MyException : public std::exception
{
public:
MyException(std::string str) : m_str(str) {}
virtual const char * what() const throw () {return m_str.c_str(); }
protected:
std::string m_str;
};
Sun C++ 5.8 Patch 121017-22 2010/09/29: Warning Function MyException::~MyException() can throw only the exceptions thrown by the function std::exception::~exception() it overrides
g++ 3.4.3: Error looser throw specifier for `virtual MyException::~MyException()'
Visual Studio 2005: It is very happy (neither error or warning)
class exception {
public:
exception () throw();
exception (const exception&) throw();
exception& operator= (const exception&) throw();
virtual ~exception() throw();
virtual const char* what() const throw();
}
I know what the problem is and how I can fix it:
class MyException : public std::exception
{
public:
MyException(std::string str) : m_str(str) {}
virtual const char * what() const throw () {return m_str.c_str(); }
~MyException() throw() {} <------------ now it is fine!
protected:
std::string m_str;
};
However I am wondering what the standard says in specific situation.
I ran another small test in Visual Studio 2005 and I have found something that really surprise me:
struct Base
{
virtual int foo() const throw() { return 5; }
};
struct Derived : public Base
{
int foo() const { return 6; }
};
int main()
{
Base* b = new Derived;
std::cout << b->foo() << std::endl; //<-- this line print 6!!!
delete b;
}
The signature of the two functions are different. How can this work? It seems that visual studio 2005 completely ignore the exception specification.
struct Base
{
virtual int foo() const throw() { return 5; }
};
struct Derived : public Base
{
int foo() { return 6; } // I have removed the const keyword
// and the signature has changed
};
int main()
{
Base* b = new Derived;
std::cout << b->foo() << std::endl; // <-- this line print 5
delete b;
}
Is this c++ standard? Is there any magic flag to set?
What about VS2008 and VS2010?
Your program is ill-formed as per the C++ Standard and hence demonstrates a behavior which cannot be explained within the realms of the C++ standard.
Reference:
C++03 Standard:
15.4 Exception specifications [except.spec]
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-specificationof the base class virtual function.
[Example:
struct B
{
virtual void f() throw (int, double);
virtual void g();
};
struct D: B
{
void f(); // ill-formed
void g() throw (int); // OK
};
The declaration of D::f is ill-formed because it allows all exceptions, whereas B::f allows only int and double. ]
It evolved a bit in C++11 [except.spec]:
5/ 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.
So you are never actually allowed to specify a looser exception specification.
However this case is tricky because the destructor is actually synthetized by the compiler itself!
In C++03, I think the Standard was not so careful about those, and you had to write them yourself, in C++11 however we get:
14/ An implicitly declared special member function (Clause 12) shall have an exception-specification. If f is an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T if and only
if T is allowed by the exception-specification of a function directly invoked by f’s implicit definition; f shall allow all exceptions if any function it directly invokes allows all exceptions, and f shall allow no exceptions if every function it directly invokes allows no exceptions.
Where the compiler will generate the exception specification of the destructor so that it matches what can be thrown from the functions it calls (ie, the destructors of the attributes). If those destructors do not throw, then it will generate a noexcept destructor which will satisfy the base class constraint.
Note: VS2005 is one of the least Standard compliant compiler you might find on Earth.

How to override non-virtual functions?

The very new syntax of override allows to let the compiler to report an error, if one does not really override a virtual function N3206.
class Base {
virtual void vfunc();
void afunc();
};
The following cases will be an error in class Derived : public Base, as mentioned in the Std examples:
void vfunk() override; // err: typo
void vfunc(int) override; // err: argument
void vfunc() const override; // err: cv
But what if the base method is not virtual?
void afunk() override; // ?
void afunc(int) override; // ?
void afunc() const override // ?;
The spec draft (n3242) says
If a virtual function is marked with the virt-specifier override and does not override a member function of a base class, the program is ill-formed.
Since the function declarations you show are not virtual, you also run afoul of
A virt-specifier-seq shall contain at most one of each virt-specifier. The virt-specifiers override and final shall only appear in the declaration of a virtual member function.
Note that a function that has the same name and parameter list (including constness) as a base function, but that is not virtual does not override that base function. It is instead said to hide the base function.
Designating that a function hides a base function by putting new instead of override after the function's declaration was part of the C++0x draft, but will not be part of C++0x as there were problems with finding syntax spots for non-function members for putting new at, in time. Consequently, it was voted out for C++0x.