I have a class hierarchy that works approximately like this:
class A
{
protected:
virtual void f(int) = 0;
};
class B
{
protected:
virtual void f(char*) = 0;
};
class DA : A
{
private:
virtual void f(int) override {}
};
class DB : public DA, B
{
private:
virtual void f(char*) override {}
};
When I try to compile with clang (or gcc, for that matter), it gives me the warning
<source>:22:18: warning: 'DB::f' hides overloaded virtual function [-Woverloaded-virtual]
virtual void f(char*) override {}
^
<source>:16:18: note: hidden overloaded virtual function 'DA::f' declared here: type mismatch at 1st parameter ('int' vs 'char *')
virtual void f(int) override {}
^
Which I understand, but should it really give that warning? After all, DB cannot even see the hidden function (which might even be named the same by coincidence).
If it wasn't private, I could use
using DA::f;
to clarify, of course, but the function is private, DB doesn't even know about it, and certainly shouldn't expose it.
Is there a way to fix this without deactivating that warning, i.e. telling the compiler that everything is designed as is intended?
After all, DB cannot even see the hidden function (which might even be named the same by coincidence).
Accessibility and visibility are different concepts in C++. DA::f() is by default visible inside DB (and then hidden by DB::f()), but it is not accessible, because it is private inside DA, and DB is not a friend of DA. One could argue that hiding a function that is inaccessible is harmless, because it cannot be called anyway. However, the distinction between hidden and inaccessible can be significant because visible and inaccessible functions do participate in overload resolution. If db is an object of type DB, then what does db.f(0) do? If DA::f() is visible but inaccessible, it will be selected as best match and the compiler will emit a diagnostic because it is inaccessible and therefore cannot be called. If DA::f() is hidden, however, the compiler will select the overload that accepts a pointer instead, and treat the literal 0 as a null pointer.
What I ended up doing (for now) is using composition instead of private inheritance. So my code currently looks like
class A
{
protected:
virtual void f(int) = 0;
};
class B
{
protected:
virtual void f(char*) = 0;
};
class DA
{
class D : A
{
private:
virtual void f(int) override {}
} d;
};
class DB : public DA
{
class D : B
{
private:
virtual void f(char*) override {}
} d;
};
I'm not 100% happy with this, as the d members cause additional syntactial overhead, but at least it works without changing the public interface.
A possible way to fix the warning is to duplicate code of DA::f inside DB:
class DB : public DA, B
{
virtual void f(int i) override
{
// copy implementation of DA::f(int) as you cannot do
// return DA::f(i);
}
private:
virtual void f(char*) override {}
};
Demo
but a local pragma to remove warning seems more appropriate.
Related
Lets say I have a class A, B and C
class A{
public:
virtual void f4(){
cerr<<"A::f4()"<<endl;
}
};
class B: public A{
public:
virtual void f4(int n){
cerr<<"B::f4("<<n<<")"<<endl;
}
};
class C: public B{
public:
virtual void f4(int n = 1){
cerr<<"C::f4("<<n<<")"<<endl;
}
};
If I have:
C c;
A& rac = c;
rac.f4();
I was expecting c's version of f4 to be called but that's not what happens. Can someone explain?
Compiling with clang -Wall the following warnings occur:
main.cpp:14:22: warning: 'B::f4' hides overloaded virtual function [-Woverloaded-virtual]
virtual void f4(int n){
^
main.cpp:6:22: note: hidden overloaded virtual function 'A::f4' declared here: different number of parameters (0 vs 1)
virtual void f4(){
^
These warnings explain what's going on. A virtual function is only overridden by another function with the same signature.
B::f4(int) does not override A::f4() because they have different parameter lists. Instead, it is a different virtual function.
So rac.f4() just calls A::f4() which is not overridden.
Since C++11 you can help to detect this problem:
virtual void f4(int n) override {
// ^^^^^^^^
Then the compiler will give an error if this function does not actually override something from the base.
Because the signatures of f4 don't match between A and B/C classes.
This is A's function signature for f4:
void A::f4() // no parameters
B and C use this function signature
void B::f4(int n)
If you are doing to override a method, it needs to have the same return type and identical parameter list. Otherwise, even if the method in the derived class has the same name as the parent class, C++ will don't consider that an override.
FWIW, C::f4 does override B::f4. The default parameter you introduce on class C doesn't influence the virtual methods override behavior. And this is the exact reason why, on my team, we disallow overloading methods with different signatures and banning default parameters. Because it leads to bugs like this.
Here's C's v-table (the methods available on it):
void C::f4(); // no parameters, overrides A::f4()
void C::f4(int n); // overrides B::f4()
Summary
I relied on the compiler to point to every location in my code I would need to update while changing the signature of a member function in a parent class, but the compiler failed to point out an overridden instance of that function in a child class, causing a logical error in my program. I would like to re-implement the classes so that I can rely more on the compiler while making changes of this kind.
Details via an example
I have the following classes:
class A
{
public:
void foo();
virtual void bar();
}
class B: public A
{
public:
void bar();
}
This is the implementation:
void A:foo(){ ... bar(); ... }
void A:bar(){ ... }
void B:bar(){ ... }
Note that whhen I call b->foo() (where b has type B* and B is a subclass of A) the bar() method called is B:bar()
After changing the type-signature of A:bar(), to say A:bar(some_parameter), my code looked like this:
void A:foo(){ ... bar(param); ... }
void A:bar(param) { ... }
void B:bar(){ ... }
Now, when I call b->foo(), of course A:bar(param) is called. I expected such a case to be caught by the compiler, but I realize now that it cannot.
How would I implement classes A & B to avoid bugs of this class.
I expected such a case to be caught by the compiler, but I realize now
that it cannot do so.
Actually, it can do so. You can use override on B::bar's declaration, and the compiler will error if there is no suitable base class function for it to override.
The way to detect this issue in c++03 where it did not have yet the override specifier (It is since c++11 standard) is to do pure virtual method in an interface. If you change the sign of a pure virtual method, all its subclasses must change it too or they will not compile.
Do not depend on concrete classes. Depend on interfaces. You will do better designs.
Your design would change to something like this:
class IA
{
public:
void foo() { ... bar(); ...}
virtual void bar() = 0;
virtual ~IA() {}
};
class A : public IA
{
public:
void bar() {...}
};
class B : public IA
{
public:
void bar() {...}
};
Now, if you change the sign of bar in the interface, all its subclasses must change it too.
This has the feeling of a complete newbie question, but why does the following code not compile when the final specifier is used for B::operator()?
struct A
{
virtual void operator()() const = 0;
};
// the CRTP-component is not really necessary here
// but it possibly makes more sense in that it could be applied like this in reality
//
template<typename Derived>
struct B : A
{
virtual void operator()() const override final
{
static_cast<Derived const&>(*this).operator()();
}
};
struct C : B<C>
{
void operator()() const
{
//do something
}
};
int main()
{
C()();
}
G++ prints the following error message:
main.cpp:17:14: error: virtual function 'virtual void C::operator()() const'
void operator()() const
^
main.cpp:9:22: error: overriding final function 'void B<Derived>::operator()() const [with Derived = C]'
virtual void operator()() const override final
^
I would have thought it works as the non-virtual C::operator() does not override the virtual functions in its base classes? How can I bring this to work (--without changing the name of C::operator())?
EDIT: As pointed out by several users, the answer is simply that the virtual-keyword in the derived class is redundant (whereas I thought leaving it out would prevent from inheriting). However, the goal I had in asking this -- namely a consistent interface throughout the dynamic and static inheritance hierarchy -- can be solved by using a non-virtual operator[] throughout and couple classes A and B by a virtual function apply:
struct A
{
void operator()() const
{
this->apply();
}
protected:
virtual void apply() const = 0;
};
template<typename Derived>
struct B : A
{
void operator()() const
{
static_cast<Derived const&>(*this).operator()();
}
protected:
virtual void apply() const override final
{
this->operator()();
}
};
struct C : B<C>
{
void operator()() const
{
//do something
}
};
int main()
{
C()();
}
If a function is declared virtual in a base class, then a function declared with the same name and parameter list is implicitly virtual in derived classes, whether or not you use the virtual keyword. You cannot make C::operator()() non-virtual.
A function in a derived class with the same signature as a virtual function in a base class overrides that virtual function from the base class. That makes it a virtual function, even if/though the declaration in the derived class doesn't use the virtual key word.
That can't be changed, so if you really need to have a function with the same name in a derived class that doesn't override the virtual function from the base class (and in the process, become virtual itself and in this case, violate the final in B) you'll need to change the signature of the function in the derived class. That can mean a different name, different parameter list, or different qualifiers. I'd treat the latter two with extreme caution though--the compiler will be able to sort out the mess you've made, but many human readers may (very easily) be surprised.
If I were reviewing such code, I'd probably cite this as a problem, and the author would need to provide very solid reasoning for why it was truly necessary to get it approved.
As an override (because it has the same signature as the virtual function in a base class), the override conflicts with the final specified in its base class.
One fix (or rather workaround) is to give that function a defaulted argument, so that it has a different type and hence not an override, and a better approach is to fix the design.
Wikipedia has the following example on the C++11 final modifier:
struct Base2 {
virtual void f() final;
};
struct Derived2 : Base2 {
void f(); // ill-formed because the virtual function Base2::f has been marked final
};
I don't understand the point of introducing a virtual function and immediately marking it as final. Is this simply a bad example, or is there more to it?
Typically final will not be used on the base class' definition of a virtual function. final will be used by a derived class that overrides the function in order to prevent further derived types from further overriding the function. Since the overriding function must be virtual normally it would mean that anyone could override that function in a further derived type. final allows one to specify a function which overrides another but which cannot be overridden itself.
For example if you're designing a class hierarchy and need to override a function, but you do not want to allow users of the class hierarchy to do the same, then you might mark the functions as final in your derived classes.
Since it's been brought up twice in the comments I want to add:
One reason some give for a base class to declare a non-overriding method to be final is simply so that anyone trying to define that method in a derived class gets an error instead of silently creating a method that 'hides' the base class's method.
struct Base {
void test() { std::cout << "Base::test()\n"; }
};
void run(Base *o) {
o->test();
}
// Some other developer derives a class
struct Derived : Base {
void test() { std::cout << "Derived::test()\n"; }
};
int main() {
Derived o;
o.test();
run(&o);
}
Base's developer doesn't want Derived's developer to do this, and would like it to produce an error. So they write:
struct Base {
virtual void test() final { ... }
};
Using this declaration of Base::foo() causes the definition of Derived to produce an error like:
<source>:14:13: error: declaration of 'test' overrides a 'final' function
void test() { std::cout << "Derived::test()\n"; }
^
<source>:4:22: note: overridden virtual function is here
virtual void test() final { std::cout << "Base::test()\n"; }
^
You can decide if this purpose is worthwhile for yourself, but I want to point out that declaring the function virtual final is not a full solution for preventing this kind of hiding. A derived class can still hide Base::test() without provoking the desired compiler error:
struct Derived : Base {
void test(int = 0) { std::cout << "Derived::test()\n"; }
};
Whether Base::test() is virtual final or not, this definition of Derived is valid and the code Derived o; o.test(); run(&o); behaves exactly the same.
As for clear statements to users, personally I think just not marking a method virtual makes a clearer statement to users that the method is not intended to be overridden than marking it virtual final. But I suppose which way is clearer depends on the developer reading the code and what conventions they are familiar with.
For a function to be labelled final it must be virtual, i.e., in C++11 ยง10.3 para. 2:
[...] For convenience we say that any virtual function overrides itself.
and para 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. [...]
i.e., final is required to be used with virtual functions (or with classes to block inheritance) only. Thus, the example requires virtual to be used for it to be valid C++ code.
EDIT: To be totally clear: The "point" asked about concerns why virtual is even used. The bottom-line reason why it is used is (i) because the code would not otherwise compile, and, (ii) why make the example more complicated using more classes when one suffices? Thus exactly one class with a virtual final function is used as an example.
It doesn't seem useful at all to me. I think this was just an example to demonstrate the syntax.
One possible use is if you don't want f to really be overrideable, but you still want to generate a vtable, but that is still a horrible way to do things.
Adding to the nice answers above - Here is a well-known application of final (very much inspired from Java). Assume we define a function wait() in a Base class, and we want only one implementation of wait() in all its descendants. In this case, we can declare wait() as final.
For example:
class Base {
public:
virtual void wait() final { cout << "I m inside Base::wait()" << endl; }
void wait_non_final() { cout << "I m inside Base::wait_non_final()" << endl; }
};
and here is the definition of the derived class:
class Derived : public Base {
public:
// assume programmer had no idea there is a function Base::wait()
// error: wait is final
void wait() { cout << "I am inside Derived::wait() \n"; }
// that's ok
void wait_non_final() { cout << "I am inside Derived::wait_non_final(); }
}
It would be useless (and not correct) if wait() was a pure virtual function. In this case: the compiler will ask you to define wait() inside the derived class. If you do so, it will give you an error because wait() is final.
Why should a final function be virtual? (which is also confusing) Because (imo) 1) the concept of final is very close to the concept of virtual functions [virtual functions has many implementations - final functions has only one implementation], 2) it is easy to implement the final effect using vtables.
I don't understand the point of introducing a virtual function and immediately marking it as final.
The purpose of that example is to illustrate how final works, and it does just that.
A practical purpose might be to see how a vtable influences a class' size.
struct Base2 {
virtual void f() final;
};
struct Base1 {
};
assert(sizeof(Base2) != sizeof(Base1)); //probably
Base2 can simply be used to test platform specifics, and there's no point in overriding f() since it's there just for testing purposes, so it's marked final. Of course, if you're doing this, there's something wrong in the design. I personally wouldn't create a class with a virtual function just to check the size of the vfptr.
While refactoring legacy code (e.g. removing a method that is virtual from a mother class), this is useful to ensure none of the child classes are using this virtual function.
// Removing foo method is not impacting any child class => this compiles
struct NoImpact { virtual void foo() final {} };
struct OK : NoImpact {};
// Removing foo method is impacting a child class => NOK class does not compile
struct ImpactChildClass { virtual void foo() final {} };
struct NOK : ImpactChildClass { void foo() {} };
int main() {}
Here is why you might actually choose to declare a function both virtual and final in a base class:
class A {
void f();
};
class B : public A {
void f(); // Compiles fine!
};
class C {
virtual void f() final;
};
class D : public C {
void f(); // Generates error.
};
A function marked final has to be also be virtual. Marking a function final prevents you from declaring a function with the same name and signature in a derived class.
Instead of this:
public:
virtual void f();
I find it useful to write this:
public:
virtual void f() final
{
do_f(); // breakpoint here
}
protected:
virtual void do_f();
The main reason being that you now have a single place to breakpoint before dispatching into any of potentially many overridden implementations. Sadly (IMHO), saying "final" also requires that you say "virtual."
I found another case where for virtual function is useful to be declared as final. This case is part of SonarQube list of warnings. The warning description says:
Calling an overridable member function from a constructor or destructor could result in unexpected behavior when instantiating a subclass which overrides the member function.
For example:
- By contract, the subclass class constructor starts by calling the parent class constructor.
- The parent class constructor calls the parent member function and not the one overridden in the child class, which is confusing for child class' developer.
- It can produce an undefined behavior if the member function is pure virtual in the parent class.
Noncompliant Code Example
class Parent {
public:
Parent() {
method1();
method2(); // Noncompliant; confusing because Parent::method2() will always been called even if the method is overridden
}
virtual ~Parent() {
method3(); // Noncompliant; undefined behavior (ex: throws a "pure virtual method called" exception)
}
protected:
void method1() { /*...*/ }
virtual void method2() { /*...*/ }
virtual void method3() = 0; // pure virtual
};
class Child : public Parent {
public:
Child() { // leads to a call to Parent::method2(), not Child::method2()
}
virtual ~Child() {
method3(); // Noncompliant; Child::method3() will always be called even if a child class overrides method3
}
protected:
void method2() override { /*...*/ }
void method3() override { /*...*/ }
};
Compliant Solution
class Parent {
public:
Parent() {
method1();
Parent::method2(); // acceptable but poor design
}
virtual ~Parent() {
// call to pure virtual function removed
}
protected:
void method1() { /*...*/ }
virtual void method2() { /*...*/ }
virtual void method3() = 0;
};
class Child : public Parent {
public:
Child() {
}
virtual ~Child() {
method3(); // method3() is now final so this is okay
}
protected:
void method2() override { /*...*/ }
void method3() final { /*...*/ } // this virtual function is "final"
};
virtual + final are used in one function declaration for making the example short.
Regarding the syntax of virtual and final, the Wikipedia example would be more expressive by introducing struct Base2 : Base1 with Base1 containing virtual void f(); and Base2 containing void f() final; (see below).
Standard
Referring to N3690:
virtual as function-specifier can be part of decl-specifier-seq
final can be part of virt-specifier-seq
There is no rule having to use the keyword virtual and the Identifiers with special meaning final together. Sec 8.4, function definitions (heed opt = optional):
function-definition:
attribute-specifier-seq(opt) decl-specifier-seq(opt) declarator virt-specifier-seq(opt) function-body
Practice
With C++11, you can omit the virtual keyword when using final. This compiles on gcc >4.7.1, on clang >3.0 with C++11, on msvc, ... (see compiler explorer).
struct A
{
virtual void f() {}
};
struct B : A
{
void f() final {}
};
int main()
{
auto b = B();
b.f();
}
PS: The example on cppreference also does not use virtual together with final in the same declaration.
PPS: The same applies for override.
I think most of the answers miss an important point. final means no more override after it has been specified. Marking it on a base class is close to pointless indeed.
When a derived class might get derived further, it can use final to lock the implementation of a given method to the one it provided.
#include <iostream>
class A {
public:
virtual void foo() = 0;
virtual void bar() = 0;
};
class B : public A {
public:
void foo() final override { std::cout<<"B::foo()"<<std::endl; }
void bar() override { std::cout<<"B::bar()"<<std::endl; }
};
class C : public B {
public:
// can't do this as B marked ::foo final!
// void foo() override { std::cout<<"C::foo()"<<std::endl; }
void bar() override { std::cout<<"C::bar()"<<std::endl; }
};
Let's suppose we have a base class which has a virtual method:
class BaseClass
{
virtual void MethodToOverride() const
{
DoSomething();
}
};
And a derived class which overrides the method (depending on the situation we can make it again virtual or not):
class DerivedClass : public BaseClass
{
void MethodToOverride() const
{
DoSomethingElse();
}
}
If we make a mistake, for example defining the MethodToOverride non const or with a wrong character, we simply define a new method, for example:
void MethodToOverride() {} // I forgot the const
void MthodToOverride() const {} // I made a typo
So this compiles fine, but causes unwanted behavior at runtime.
Is there any way to define a function as an explicit override of an existing one, so the compiler warns me if I define it wrongly? Something like (I know it does not exist):
void MethodToOverride() const overrides BaseClass::MethodToOverride() const {}
The best way is to declare the method to be pure virtual in BaseClass.
class BaseClass
{
virtual void MethodToOverride() const = 0;
};
If implementing classes are inherited again (which I would put in question as a semi good practice), there is no way to control the correct implementation.
[[override]] attribute. However it is a part of C++0x.
If you are using gcc consider the -Woverloaded-virtual command-line option.
C++0x offers an attribute for this (see vitaut's answer), and e.g. Visual C++ offers a language extension.
But in portable C++98 the best you can do is a sanity check, that the base class offers an accessible member function that accepts the same arguments, like ...
// The following macro is mainly comment-like, but performs such checking as it can.
#define IS_OVERRIDE_OF( memberSpec, args ) \
suppressUnusedWarning( sizeof( (memberSpec args, 0) ) )
where
template< typename T >
inline void suppressUnusedWarning( T const& ) {}
You call the macro in your override implementation, with the function's actual arguments.
EDIT Added call example (disclaimer: untouched by compiler's hands):
class BaseClass
{
protected:
virtual void MethodToOverride() const
{
DoSomething();
}
};
class DerivedClass : public BaseClass
{
protected:
void MethodToOverride() const
{
IS_OVERRIDE_OF( BaseClass::MethodToOverride, () );
DoSomethingElse();
}
};
Using such a sanity check can improve the clarity of the code in certain cases, and can save your ass in certain cases. It has three costs. (1) Someone Else might mistake it for a guarantee, rather than just an informative comment and partial check. (2) the member function can't be private in the base class, as it is in your example (although that's perhaps positive). (3) Some people react instinctively negatively to any use of macros (they've just memorized a rule about badness without understanding it).
Cheers & hth.,
If your base class may be an abstract one, then the solution is to make the methods you want to be overriden pure virtual. In this case the compiler will yell if you try to instantiate the derived class. Note that pure virtual functions can also have definitions.
E.g.
class BaseClass
{
virtual void MethodToOverride() const = 0;
//let's not forget the destructor should be virtual as well!
};
inline void BaseClass::MethodToVerride const()
{
DoSomething();
}
//note that according to the current standard, for some inexplicable reasons the definition
//of a pure virtual function cannot appear 'inline' in the class, only outside
If you cannot afford your base class to be abstract, then C++03 gives little to do and #vitaut's answer gives what you need for C++0x.
There was a sentence in your question which alarmed me. You say you can choose to make the method further virtual or not. Well, you can't, in C++03. If the method has been declared virtual it will be virtual throughout the hierarchy, whether you explicitly specify it or not. E.G.
class A
{
virtual void f(){}
} ;
class B: public A
{
void f(); //same as virtual void f();
};
You can try this: :)
#include <iostream>
using namespace std;
class Base
{
public:
virtual void YourMethod(int) const = 0;
};
class Intermediate : private Base
{
public:
virtual void YourMethod(int i) const
{
cout << "Calling from Intermediate : " << i << "\n";
}
};
class Derived : public Intermediate, private Base
{
public:
void YourMethod(int i) const
{
//Default implementation
Intermediate::YourMethod(i);
cout << "Calling from Derived : " << i << "\n";
}
};
int main()
{
Intermediate* pInterface = new Derived;
pInterface->YourMethod(10);
}
I think the code speaks for itself. Base makes sure you implement the function with the correct signature (As a side effect makes you always implement it, even though you can use default behavior) while Intermediate which is the interface makes sure that there is a default implementation. However, you are left with a warning :).