C++: override or overload? - c++

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.

Related

Can a derived class redefine virtual function with a function of different signature?

There is somewhat odd sample given in one of the Microsoft documentation pages , which consists of two classes, one is a base class and another one is a derived. The base class has the following virtual function member:
virtual void setEars(string type) // virtual function
{
_earType = type;
}
And another, defined in the derived class, which, as stated in comments, redefines the virtual function:
// virtual function redefined
void setEars(string length, string type)
{
_earLength = length;
_earType = type;
}
These two have different signatures and I haven't ever heard if you actually can redefine a virtual function with a function of a different signature. I compiled this sample and could find any overriding behavior between these two. Is the sample just misleading or I'm missing something?
Is the sample just misleading or I'm missing something?
This example is indeed misleading.
When overriding a virtual function in a derived type, it must come with the same signature as it is defined in the base class. If that is not the case, the function in the child class will be considered as its own entity and is not considered in a polymorphic function call. Additionally, it will hide the name of the base classes function, which is considered bad practice, as it violates the "is-a" relationship in public inheritance.
In order to prevent such accidental hiding, C++ introduced the override keyword. When overriding a virtual function, it then must have a matching signature, otherwise, the compiler will reject it.

Purpose of making overridden virtual function non-virtual

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.

Deriving implementation of pure virtual function

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.

Implementation of inherited class' method (param=pointer to parent) in child class (param=pointer to child)

Say if I have an interface with virtual methods, but one of the arguments are:
virtual void Delete(ParentClass *parentClass) = 0;
If I later implement this in child class
void Delete(ChildClass *childClass)
{
};
...why doesn't this work as an implementation?
As the function prototype differs (one uses ParentClass and the other ChildClass) they are not the same functions. Instead the one with the ChildClass argument is overloading and not overriding the Delete function.
C++03 Standard: 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 and same parameter list as Base::vf is declared, then Derived::vf is also virtual an it overrides Base::vf.
Note the text in bold.
An derived class function overides a Base class function only and only if it has the same signature as the Base class function with the exception of Co-Variant return types. Since your function Delete() does not have the same signature in Base Class and Derived class, the derived class function is not overidding the Base class function but what you get is merely Function Hiding.
C++03 Standard: 3.3.7/1:
A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class.
Because any type that's accepted as an argument for the base-class function, must also be acceptable by an override of that function. This prevents an error such as:
struct BastardClass : ParentClass {} wrong;
Delete(&wrong);
which, if dispatched to the override that expects a ChildClass, would cause it to interpret the object as the wrong type.
(This is known as contravariance - arguments to a function overridden by a more specific type must be no more specific than those being overridden. For similar reasons, return types must be covariant - those specified by a function overridden by a more specific type must be no less specific.)

C++ Virtual Const Function

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]] () {
....
}
};