Overloading Base class method with extra default parameter in Derived - c++

My base class offers a virtual method with no arguments, like this:
class Base{
virtual void myMethod(void) = 0;
};
I would like to override it in the Derived class and offer an implementation (the Derived class is not supposed to be an abstract type), and additionally provide an optional parameter via setting the default value, as so:
class Derived : public Base{
void myMethod(Thing *optional = NULL) { ... }
};
But I seem to be getting the error of the type:
error: cannot allocate an object of abstract type 'Derived'
because the following virtual functions are pure within 'Derived':
virtual void myMethod()
Now, I know that when overloading functions, the following functions can not exist along each other:
void myFunction();
void myFunction(Thing *optional = NULL);
because the function call myFunction() would match both declared functions. Following this logic, my definition in Derived should override the Base method with no arguments, and "add another method" with one argument, but it doesn't.
I know I can solve this problem by definitions like this:
class Derived : public Base{
void myMethod(Thing *optional) { ... }
void myMethod() { myMethod(NULL); }
};
My question is: is this really the only way to achieve the desired functionality? If so, why is what I am trying not allowed and not compiled as I would expect?

Yes, what you propose as the last code block is the right way to solve this.
Your first attempt does not work because you are defining a method with one argument, and the virtual method you are trying to override has zero. Giving arguments default values does not change the number of arguments the function takes, and therefore it does not match the no-arg overload in order to override it. All it does is instruct the compiler to insert the default value at any call sites that omit it, and in this case such a call would be ambiguous between the no-arg version and the one-arg version with a default value for the parameter.

Related

Base class function being called instead of overridden function defined in Derived class

Here are my code
#include <iostream>
using namespace std;
class BaseClass
{
public:
BaseClass() {}
void init(const int object) { cout<<"BaseClass::init"<<endl; }
void run(const int object) { cout<<"BaseClass::run calls =>"; init(object); }
};
class Derived : public BaseClass {
public:
Derived() {}
void init(const int object) { cout<<"Derived::init"<<endl; }
};
int main() {
BaseClass b;
b.init('c');
b.run('c');
Derived d;
d.init(5); // Calls Derived::init
d.run(5); // Calls Base::init. **I expected it to call Derived::init**
}
And here is generated output
BaseClass::init
BaseClass::run calls =>BaseClass::init
Derived::init
BaseClass::run calls =>BaseClass::init
With call d.run(5), Why "BaseClass::init" is being called instead of "Derived::init" ?
I though we need virtual functions only when calling through a pointer.
What is the rationale behind keeping such behavior ?
Why "BaseClass::init" is being called instead of "Derived::init" ?
Because init is a non-virtual member function. To have the desired effect, you need to make init a virtual member function as shown below:
class BaseClass
{
public:
BaseClass() {}
//NOTE THE VIRTUAL KEYWORD HERE
virtual void init(const int object) { cout<<"BaseClass::init"<<endl; }
//other member function here as before
};
Demo
I though we need virtual functions only when calling through a pointer.
Note that the statement init(object); is equivalent to writing
this->init(object); //here `this` is a pointer
When you wrote:
d.run(5);
In the above statement, first the address of object d is implicitly passed as the first argument to the implicit this parameter of member function run. The type of this implicit this parameter is BaseClass* and this happens due to derived to base conversion. Now, the call init(object); is equivalent to this->init(object);. But since init is a non-virtual member function, the call is resolved at compile time meaning the base class init will be called.
Basically when a member function is called with a derived class object, the compiler first looks to see if that member exists in the derived class. If not, it begins walking up the inheritance chain and checking whether the member has been defined in any of the parent classes. It uses the first one it finds. This means for the call d.run(5) the search for a member function named run starts inside the derived class. But since there is no function named run inside derived class, the compiler looks into the direct base class BaseClass and finds the member function named run. So it stops its search and uses this found run member function. And as i said, in your example, init is non-virtual and so the call is resolved at compile time to the base class run.
On the other hand, if we make init to be a virtual member function, then this call will be resolved at run-time meaning the derived class init will be called.
I though we need virtual functions only when calling through a pointer.
No. Thats not right. You need to make a function virtual when you want to enable calling it based on the dynamic type of the object. And once you do have a virtual function you can use pointers or references to make use of the virtual dispatch.
You need to make a method virtual when you want to override it. As BaseClass::run is not overridden by Derived::run, there is no virtual dispatch and calling init from BaseClass::run calls BaseClass::init. If you want to enable virtual dispatch for BaseClass::init you need to declare it virtual.
Further, consider that your code is equivalent to:
void run(const int object) {
cout<<"BaseClass::run calls =>";
this->init(object);
}
this is BaseClass*, hence BaseClass::init is called. You are calling init via a pointer, but that does not matter because init is not virtual. If you want to call init based on the dynamic type of the object, thats exactly what virtual is good for. The "overhead" you refer to in comments is not really overhead, but just the minimum needed to get the behavior you want. If you can change the design and do not need runtime polymorphism you can take a look at CRTP wich is a form of static polymorphism.

C++ - Overloading vs Overriding in Inheritance

As far as I learned, Overriding is when you have 2 functions which have the same name and function return type (void, int, float.. etc) and the same parameter numbers and types.
And the overloading is when you have 2 functions which have the same name but either Parameter number/types or function return type should be different.
But today when I was in the class, I saw this slide:
Shouldn't this be overloading? Not overriding? Because here the return type changed (from void
to float) and fa1() function in the base class had no parameter, but in the derived class it has float parameter.
If this is overriding, why?
In C++, any method in a derived class only overrides the method in the base class if their declarations match (I say "match" but I don't know the formal term for that). That is, all arguments must have the same type, and const qualification of this must be the same. If anything there mismatches, the method in the derived class hides all methods with the same name, instead of overriding. This is what the "ERROR" in your picture tries to tell you. So // overrides in a comment in that picture is incorrect and misleading.
Yes, many C++ teachers actually don't understand these somewhat obscure details.
BTW additionally, if you want to override, the method in your base class should be virtual; otherwise, polymorphism won't work. If it was not virtual, we also say that the derived-class method hides the base-class method. Here, however, the part about hiding has almost no meaning; what this term really wants to express is that you're not overriding.
In addition, overloading is, as you noticed, presence of several methods with the same name but different signatures. They should all be present in the derived class to be useful - if the derived class has only one method fa1, and the other fa1 are in the base, they will be hidden. However, there is syntax sugar which "copies" all fa1 from base to derived, disabling all that hiding semantics:
class A
{
public:
void fa1();
void fa1(int);
};
class B: public A
{
public:
using A::fa1;
void fa1(int, int);
};
...
B b;
b.fa1(); // calls A::fa1()
b.fa1(4); // calls A::fa1(int)
b.fa1(4, 8); // calls B::fa1(int, int)
The part about hiding is rarely, if ever, useful. When overriding, you should tell this to your compiler - use the override keyword for that. The compiler will then check that your code works as you intended.
class A
{
public:
virtual void fa1(int) {}
void fa2(int) {}
};
class B: public A
{
public:
void fa1(int) override {} // OK
void fa1() override {} // ERROR: doesn't really override - different signature
void fa2(int) override {} // ERROR: doesn't really override - not virtual in base
};
ia1 not overloading. First you can't overload variables. So ia1 is definitely an override. And it's also a dangerous thing. At my company, our coding standards disallow overriding variable names in any situation. It just leads to confusion.
fa1 though -- that looks like an overload. The base class fa1() takes no arguments, but the subclass version takes a float.

Is there reverse of 'override' specifier in C++?

override keyword allows to make sure that the function will get overridden.
I am looking for the reverse functionality. So that - when I write a new function - I want to mark it with something to make sure it will not get accidentally overwritten.
(Also, I do not want to make it static, since it looks like to belong to an object rather than class)
I want to mark it with something to make sure it will not get accidentally overwritten.
You can use the final specifier. Example from cppreference:
struct Base
{
virtual void foo();
};
struct A : Base
{
void foo() final; // A::foo is overridden and it is the final override
void bar() final; // Error: non-virtual function cannot be overridden or be final
};
If you don't want a virtual function to be overridden in the derived class, you can use final:
Specifies that a virtual function cannot be overridden in a derived class or that a class cannot be inherited from.
e.g.
struct Base
{
virtual void foo() final; // foo cannot be overridden in the derived class
};
struct Derived : Base
{
void foo(); // Error: foo cannot be overridden as it's final in Base
};
final is the keyword you are looking for.
Remark: Be aware that override does not "make sure that the function will get overriden" as you put it. override in your derived class does make sure that you actually override a method of a base class, and not just introduce a new method that is similar to a virtual method of the base class.
To make sure that a method is overriden it would have to be pure virtual in your base class.
Also, static works exactly the other way round: static methods belong to the class, non-static methods need an object to be called.

Overriding overloaded methods hides some of the overloads [duplicate]

This question already has answers here:
Why does an overridden function in the derived class hide other overloads of the base class?
(4 answers)
Closed 5 years ago.
Suppose I have the following classes:
class Base
{
public:
virtual void myMethod()
{
}
virtual void myMethod(int x)
{
}
};
class Derived : public Base
{
};
In this situation the following code compiles just fine.
int main(void)
{
Derived obj;
obj.myMethod();
return (0);
}
The problem arises when I try to override one of myMethods like below.
class Derived : public Base
{
public:
virtual void myMethod(int x)
{
}
};
Now the code won't compile and gives the error:
error C2660: 'Derived::myMethod' : function does not take 0 arguments
I have overridden one of the overloaded functions and apparently this has hidden the other one from Derived class. To get rid of the error I have to override all the overloads. This is against my expectation and doesn't seem rational to me. Why does this code behave this way?
The problem can be reproduced here.
Indeed, declaring a function in one scope hides anything with the same name in a wider scope, so your override in the derived class hides the overload in the base class.
This is usually not a problem, since you'd usually interact with polymorphic classes via the base class; and usually what you want, since it prevents changes to the base class from unexpectedly changing the behaviour of code that does interact with the derived class.
But you can easily bring it back into the derived class's scope if you want:
using Base::myMethod;
or refer to the function by qualified name:
obj.Base::myMethod();
your compiler is 100% right.
you overloaded your function to take an integer as argument, then this function hid all of the base class function - so obj calls myMethod(int) be default , yet you don't provide your function an integer.
if you fix your code to be
obj.myMethod(4);
the problem solved.
when overriding a function in the derived class - it hides all the other base class overloads. one can still call the base class with this syntax :
obj.Base::myMethod();
In more in depth answer , this is WHY it happens.
first of all, we need to understand HOW the compiler compiles Object oriented code. remember - the functions compiles into assembly commands and they sit in the code segment. the variables compiles into rows of memory that sit wither in the stack , heap or data segments. functions sits in on part of the application , the variables in a complete different areas. how does the compiler compile a class with variables AND functions? well, it doesn't. the idea goes like this:
let's say a have a class named X with some variables and some functions
1) take all the member functions and bring them out of the class
2) add another argument to each-now-globally-declared functions - const X* this
3) each time you see the syntax x.someFunc(args..) change it to be someFunc(args..,&x)
4) in the functions - if you don't recognize a symbol - try attaching it a this-> and see if you can compile this
5) compile X as C struct and the other as C functions
6)do the same for derived classes
(of course , there is the virtual table issue , but let's stop here)
IN YOUR EXAMPLE:
the psuedo code that might represent the compiler parsed-code is
struct Base{}
struct Derived{}
void myMethod(const Base* this);
void myMethod(int x,const Base* this);
void myMethod(int x, const Derived* this);
//what you tried to do is :
myMethod (&obj);
but the compiler can't find any function that matches these arguments!
this is not very intuitive for someone who don't initially knows how object oriented compiles, but it makes more sense after understanding this compiling procedure.
By overriding the function in Derived class you hide all overloaded implementations of that function name existing in Base class.
Therefore overriding void Base::myMethod(int) with void Derived::myMethod(int) generates code only for void Derived::myMethod(int) and doesn't for void Derived::myMethod().
As mentioned before you can call Base's function explicitly:
obj.Base::myMethod().

Call inherited method inside template function

I have a template method in a parent class, that should call another method from the base class. It works, if the method is explicitly defined in the base class, but it doesn't work if the method is inherited. I can't figure out what's exactly wrong with this code (although I know it's a little weird :)
class A
{
protected:
virtual void someMethod()
{
}
template <class TBaseClass>
void templateMethod()
{
TBaseClass::someMethod();
}
};
class B : public A
{
};
class C : public B
{
protected:
virtual void someMethod()
{
templateMethod<A>(); // this works
templateMethod<B>(); // this doesn't
}
};
This ends up with compiler error:
error C2352: 'A::someMethod' : illegal call of non-static member function
What exactly is wrong? I'm not looking for workarounds, that's easy. I'd like to know why is this incorrect.
In template <TBaseClass> void A::templateMethod() the invocant, this, is of type A *. So when you try to call B::someMethod on it, the compiler won't recognize it a object method call, because B is not a base class, but it can still be a static method call, so the compiler will try that, find B::someMethod inherited via A and complain it is not static. The fact that A is a base class of this is not relevant; only that B is not.
The issue is that class A is not automatically granted access to class B. The methods within the class don't know that the current instance of A is actually of type B.
To do what you're trying, you need to cast A to the target type:
template <class TBaseClass>
void templateMethod()
{
static_cast<TBaseClass*>(this)->someMethod();
}
This will work if the particular instance of A you're calling really is a B (as it is in the example you give). There is no type checking done here to be sure it is. If you pass a class that is not in the inheritance hierarchy you will be in the work of undefined behavior.
That said, your example has "someMethod()" as virtual. If you're doing what I just did here then making that method virtual may not make sense, as you are explicitly saying which instance you want. If you do leave it virtual, then just calling someMethod() directly in A will get you the most derived instance.
I think it's not working because you are trying to call a static method.
Static methods can be inherited but they can't be virtual.
Thats why A::someMethod will work and B::someMethod won"t work.