Given the following snippet,
class Base
{
public:
virtual void eval() const
{
std::cout<<"Base Const Eval\n";
}
};
class Derived:public Base
{
public:
void eval()
{
std::cout<<"Derived Non-Const Eval\n";
}
};
int main()
{
Derived d;
Base* pB=&d;
pB->eval(); //This will call the Base eval()
return 0;
}
Why the pB->eval() will call the Base::eval()?
Thank you
In your Derived class, the prototype for eval doesn't match the one for the virtual function in Base. So it won't override the virtual function.
Base::eval() const;
Derived::eval(); //No const.
If you add the const for Derived::eval(), you should get virtual behavior.
You can translate in your mind:
virtual void Base::eval() const;
void Derived::eval() ;
to
void eval(const Base *this, size_t vtable_offset);
void eval(Derived *this);
and see by inspection how little the second matches the signature of the first.
This is because one is declared const and the other isn't. One function is being hidden by the other. The function in Derived is hiding the one in Base because they have the same name while they aren't the same function.
My compiler gives a warning here, does yours?
$10.3/2- "If a virtual member function
vf is declared in a class Base and in
a class Derived, derived directly or
indirectly from Base, a member
function vf with the same name,
parameter-type-list (8.3.5),
cv-qualification, and refqualifier (or
absence of same) as Base::vf is
declared, then Derived::vf is also
virtual (whether or not it is so
declared) and it overrides111
Base::vf."
111) A function with the same name but
a different parameter list (Clause 13)
as a virtual function is not
necessarily virtual and does not
override. The use of the virtual
specifier in the declaration of an
overriding function is legal but
redundant (has empty semantics).
Access control (Clause 11) is not
considered in determining overriding.
As an aside, note that it does not talk about access specifications. So base class and derived class access specifiers for the overridden function could be different
This means that Derived::eval does not override Base::eval as their cv qualifications differ.
The const is part of the function signature. In order to override a function the override must have exactly the same signature as the base version - in this case it does not.
Consider that the calling code doesn't need to know anything about Derived - it is calling a const function on a Base. You wouldn't expect that call to wind up in a non-const function which might change stuff about the class.
In C++0x, the situation is detectable at compile time using the base_check and override keywords. Excerpt from wikipedia:
The [[base_check]] attribute on a
class/struct means that any implicit
overriding will give rise to a
compiler error. Any overriding must be
explicitly marked with the
[[override]] attribute.
Most probably (not very sure about the syntax):
class Derived [[base_check]] : public Base {
virtual void eval [[override]] () {
....
}
};
Related
I have two classes representing contexts for some methods.
class BaseContext {};
class DerivedContext : public BaseContext {};
I have a base class:
class MyBase {
protected:
virtual void doSome(BaseContext* context);
};
And a derived class:
class MyDerived : public MyBase {
protected:
virtual void doSome(DerivedContext* context) override; // Overriding
virtual void doSome(DerivedContext* context); // Overloading?
};
Since DerivedContext derives from BaseContext, it might seems that I am overriding doSome. But it might also be an overloading...
Which one is correct? Am I overriding or overloading here?
Thus, if I type (MyBase* my = new MyDerived())->doSome(new DerivedContext()), what should I get?
This is neither overriding nor overloading. Since the parameter's type is different, MyDerived::doSome is just hiding MyBase::doSome.
1.1. Since DerivedContext derives from BaseContext, it might seems that I am overriding doSome.
No. Here're the preconditions of overriding listed in the standard. $10.3/2 Virtual functions
[class.virtual]:
(emphasis mine)
If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list ([dcl.fct]), cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides110 Base::vf.
110) A function with the same name but a different parameter list (Clause [over]) as a virtual function is not necessarily virtual and does not override.
In fact with override specifier you'll get a compile error for this case. e.g.
error: 'doSome' marked 'override' but does not override any member functions
1.2. But it might also be an overloading...
You can't overload functions across scopes according to the rule of unqualified name lookup (unless using using-declaration to introduce names into the same scope).
Thus, if I type (MyBase* my = new MyDerived())->doSome(new DerivedContext()), what should I get?
MyBase::doSome() will be invoked since you call it on a MyBase*. This is not overriding, so no dynamic dispatching happens here.
LIVE
Note the argument DerivedContext* will be implicitly converted to BaseContext* and then passed to the function. BTW (MyBase* my = new MyDerived())->... is not valid syntax.
While only specifying the member function with another argument type, you are hiding the function from the base class.
With the override specifier you should get a compile error as there is no such function (with the exact same signature) in the base class.
Overriding is when redefining virtual a member function in a derived class with the exact same arguments (number and type). The override specifier is optional but encouraged as it helps identifying subtle bugs as in your case.
Overloading is when defining a function (not necessarily member of a class) with a different number or types of arguments.
Just put override after the function definition and see if it compiles. If it compiles, it is overriding the virtual method in the base class. If it does not, it would hide the base class method.
Consider the following classes in C++11:
class Base
{
public:
virtual void foo() = 0;
}
class Sub1 : public Base
{
public:
virtual void foo() override {};
}
class Sub2 : public Base
{
public:
void foo() override {};
}
What are the consequences of making the overridden function non-virtual as in Sub2?
An override of a virtual function is always virtual regardless of whether it's declared as such. Thus, having or not having the virtual keyword in the declaration of Sub2::foo() has no effect whatsoever as far as the language is concerned, since the override keyword means that the function must override a member function of a base class. From §10.3 [class.virtual]/p2 of the standard, emphasis added:
If a virtual member function vf is declared in a class Base and in
a class Derived, derived directly or indirectly from Base, a
member function vf with the same name, parameter-type-list (8.3.5),
cv-qualification, and ref-qualifier (or absence of same) as Base::vf
is declared, then Derived::vf is also virtual (whether or not it
is so declared) and it overrides Base::vf. For convenience we say
that any virtual function overrides itself.
Omitting the word virtual does not make the function non-virtual. It does reduce the verbosity, the amount of visual noise, or in short, the way that the source code text can make an impression of just being too long-winded without any specific part of it introducing anything really new that can capture the reader's attention so that it all appears more or less like a gray mass of text, which of course can lead to some important details being overlooked, which is to say, inadvertently ignored. The override keyword is preferable.
I looked over the internet for an answer to my questions but couldn't find any, so here I am.
Is it correct to specify override to my function that derived from a pure virtual:
class baseClass
{
public:
virtual void myFunction() = 0;
}
class derivedClass : public baseClass
{
public:
virtual void myFunction() override;
}
Is this correct?
And my second question is:
Do I have to specify virtual in the derivedClass for my function even though no class will inherite from my derived class (it will be final)?
Thank you a lot for your answers!
Is this correct?
Yes. Override ensures that the function is virtual and overriding a virtual function from the base class. The program is ill-formed (a compile-time error is generated) if this is not true.
Do I have to specify virtual in the derivedClass for my function even though no class will inherite from my derived class (it will be final)?
No you don't. But even if you leave away the virtual specifier it remains virtual. Because it has been declared virtual in your BaseClass.
If some member function vf is declared as virtual in a class Base, and
some class Derived, which is derived, directly or indirectly, from
Base, has a declaration for member function with the same
name
parameter type list (but not the return type)
cv-qualifiers
ref-qualifiers
Then this function in the class Derived is also virtual (whether or
not the keyword virtual is used in its declaration) and overrides
Base::vf (whether or not the word override is used in its
declaration). Base::vf does not need to be visible (can be declared
private, or inherited using private inheritance) to be overridden.
cppreference.com
Also, please remember that you should define a virtual destructor (can be empty one) in baseClass, in order to guarantee a proper resource deallocation in the derived classes.
Consider following example
#include <iostream>
struct PureVirtual {
virtual void Function() = 0;
};
struct FunctionImpl {
virtual void Function() {
std::cout << "FunctionImpl::Function()" << std::endl;
}
};
struct NonPureVirtual : public FunctionImpl, public PureVirtual {
using FunctionImpl::Function;
};
int main() {
NonPureVirtual c;
c.Function();
}
Compiler (GCC 4.9, Clang 3.5) exits with error
test.cpp:18:20: error: variable type 'NonPureVirtual' is an abstract class
NonPureVirtual c;
^
test.cpp:4:18: note: unimplemented pure virtual method 'Function' in 'NonPureVirtual'
virtual void Function() = 0;
^
But when I don't derive form PureVirtual everything is OK. This is weird because Standard 10.4.4 says
A class is abstract if it contains or inherits at least one pure
virtual function for which the final overrider is pure virtual.
They are not saying anything about what the final overrider is but I suppose it should be FunctionImpl::Function() especially when I made it available through using directive. So why is still NonPureVirtual abstract class and how can I fix this.
FunctionImpl::Function and PureVirtual::Function are different functions from different classes.
Their respective types are void (FunctionImpl::*)() and void (PureVirtual::*)().
Since PureVirtual and FunctionImpl are unrelated classes, these function types are unrelated.
They happen to have the same name and the same parameters and return type, but since they're different, the using FunctionImpl::Function line doesn't make that function an override of the one in PureVirtual.
And if you declared a variable of type void (PureVirtual::*)(), you wouldn't be able to assign FunctionImpl::Function to it.
In other words, the final override of PureVirtual::Function is the original one in PureVirtual, which is pure virtual.
For making what you want possible, Matthieu M.'s answer (using a forwarding call) is the way to go, it seems.
You cannot use a using directive and have to resort to a fowarding call instead:
struct NonPureVirtual : public FunctionImpl, public PureVirtual {
virtual void Function() override {
return FunctionImpl::Function();
}
};
And yes, it works as expected.
You're attributing a using declaration with something that it doesn't do. What it does is (From draft n3337, 7.3.3/1):
... using-declaration introduces a name into the declarative region in which the using-declaration appears.
Later from the same paragraph:
If a using-declaration names a constructor (3.4.3.1), it implicitly declares a set of constructors in the
class in which the using-declaration appears (12.9); otherwise the name specified in a using-declaration is a
synonym for the name of some entity declared elsewhere.
In your case, FunctionImpl::Function is first declared in FunctionImpl class and it is its member. A using-declaration doesn't change that fact, as paragraph 16 says further down:
For the purpose of overload resolution, the functions which are introduced by a using-declaration into a derived class will be treated as though they were members of the derived class. In particular, the implicit this parameter shall be treated as if it were a pointer to the derived class rather than to the base class. This has no effect on the type of the function, and in all other respects the function remains a member of
the base class.
Now on to the definition of overriding (10.3/2):
If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides Base::vf. For convenience we say that any virtual function overrides itself.
And there's also the definition of a final overrider in the same paragraph.
A virtual member function C::vf of a class object S is a final overrider unless the most derived class (1.8) of which S is a base class subobject (if any) declares or inherits another member function that overrides vf. In a derived class, if a virtual member function of a base class subobject has more than one final overrider the program is ill-formed. [...]
I think that makes it clear that you can't use a using declaration to override a virtual function. A possible fix is in Matthieu's answer.
With the struct definition given below...
struct A {
virtual void hello() = 0;
};
Approach #1:
struct B : public A {
virtual void hello() { ... }
};
Approach #2:
struct B : public A {
void hello() { ... }
};
Is there any difference between these two ways to override the hello function?
They are exactly the same. There is no difference between them other than that the first approach requires more typing and is potentially clearer.
The 'virtualness' of a function is propagated implicitly, however at least one compiler I use will generate a warning if the virtual keyword is not used explicitly, so you may want to use it if only to keep the compiler quiet.
From a purely stylistic point-of-view, including the virtual keyword clearly 'advertises' the fact to the user that the function is virtual. This will be important to anyone further sub-classing B without having to check A's definition. For deep class hierarchies, this becomes especially important.
The virtual keyword is not necessary in the derived class. Here's the supporting documentation, from the C++ Draft Standard (N3337) (emphasis mine):
10.3 Virtual functions
2 If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides Base::vf.
No, the virtual keyword on derived classes' virtual function overrides is not required. But it is worth mentioning a related pitfall: a failure to override a virtual function.
The failure to override occurs if you intend to override a virtual function in a derived class, but make an error in the signature so that it declares a new and different virtual function. This function may be an overload of the base class function, or it might differ in name. Whether or not you use the virtual keyword in the derived class function declaration, the compiler would not be able to tell that you intended to override a function from a base class.
This pitfall is, however, thankfully addressed by the C++11 explicit override language feature, which allows the source code to clearly specify that a member function is intended to override a base class function:
struct Base {
virtual void some_func(float);
};
struct Derived : Base {
virtual void some_func(int) override; // ill-formed - doesn't override a base class method
};
The compiler will issue a compile-time error and the programming error will be immediately obvious (perhaps the function in Derived should have taken a float as the argument).
Refer to WP:C++11.
Adding the "virtual" keyword is good practice as it improves readability , but it is not necessary. Functions declared virtual in the base class, and having the same signature in the derived classes are considered "virtual" by default.
There is no difference for the compiler, when you write the virtual in the derived class or omit it.
But you need to look at the base class to get this information. Therfore I would recommend to add the virtual keyword also in the derived class, if you want to show to the human that this function is virtual.
The virtual keyword should be added to functions of a base class to make them overridable. In your example, struct A is the base class. virtual means nothing for using those functions in a derived class. However, it you want your derived class to also be a base class itself, and you want that function to be overridable, then you would have to put the virtual there.
struct B : public A {
virtual void hello() { ... }
};
struct C : public B {
void hello() { ... }
};
Here C inherits from B, so B is not the base class (it is also a derived class), and C is the derived class.
The inheritance diagram looks like this:
A
^
|
B
^
|
C
So you should put the virtual in front of functions inside of potential base classes which may have children. virtual allows your children to override your functions. There is nothing wrong with putting the virtual in front of functions inside of the derived classes, but it is not required. It is recommended though, because if someone would want to inherit from your derived class, they would not be pleased that the method overriding doesn't work as expected.
So put virtual in front of functions in all classes involved in inheritance, unless you know for sure that the class will not have any children who would need to override the functions of the base class. It is good practice.
There's a considerable difference when you have templates and start taking base class(es) as template parameter(s):
struct None {};
template<typename... Interfaces>
struct B : public Interfaces
{
void hello() { ... }
};
struct A {
virtual void hello() = 0;
};
template<typename... Interfaces>
void t_hello(const B<Interfaces...>& b) // different code generated for each set of interfaces (a vtable-based clever compiler might reduce this to 2); both t_hello and b.hello() might be inlined properly
{
b.hello(); // indirect, non-virtual call
}
void hello(const A& a)
{
a.hello(); // Indirect virtual call, inlining is impossible in general
}
int main()
{
B<None> b; // Ok, no vtable generated, empty base class optimization works, sizeof(b) == 1 usually
B<None>* pb = &b;
B<None>& rb = b;
b.hello(); // direct call
pb->hello(); // pb-relative non-virtual call (1 redirection)
rb->hello(); // non-virtual call (1 redirection unless optimized out)
t_hello(b); // works as expected, one redirection
// hello(b); // compile-time error
B<A> ba; // Ok, vtable generated, sizeof(b) >= sizeof(void*)
B<None>* pba = &ba;
B<None>& rba = ba;
ba.hello(); // still can be a direct call, exact type of ba is deducible
pba->hello(); // pba-relative virtual call (usually 3 redirections)
rba->hello(); // rba-relative virtual call (usually 3 redirections unless optimized out to 2)
//t_hello(b); // compile-time error (unless you add support for const A& in t_hello as well)
hello(ba);
}
The fun part of it is that you can now define interface and non-interface functions later to defining classes. That is useful for interworking interfaces between libraries (don't rely on this as a standard design process of a single library). It costs you nothing to allow this for all of your classes - you might even typedef B to something if you'd like.
Note that, if you do this, you might want to declare copy / move constructors as templates, too: allowing to construct from different interfaces allows you to 'cast' between different B<> types.
It's questionable whether you should add support for const A& in t_hello(). The usual reason for this rewrite is to move away from inheritance-based specialization to template-based one, mostly for performance reasons. If you continue to support the old interface, you can hardly detect (or deter from) old usage.
I will certainly include the Virtual keyword for the child class, because
i. Readability.
ii. This child class my be derived further down, you don't want the constructor of the further derived class to call this virtual function.