Overriding a Base's Overloaded Function in C++

Overriding a Base's Overloaded Function in C++

In class bar, add

using foo::a;

This is a common 'gotcha' in C++. Once a name match is found in the a class scope, it doesn't look further up the inheritance tree for overloads. By specifying the 'using' declaration, you bring all of the overloads of 'a' from 'foo' into the scope of 'bar'. Then overloading works properly.

Keep in mind that if there is existing code using the 'foo' class, its meaning could be changed by the additional overloads. Or the additional overloads could introduce ambiguity and and the code will fail to compile. This is pointed out in James Hopkin's answer.

Overriding overloaded methods hides some of the overloads

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.

Difference between overriding and overloading of a function in C++

overloading means functions with same name having different parameters , it does not really depend whether you are using procedural language or object oriented language you can do overloading. well as far as over riding is concerned it means we are explicitly defining a function that exist in base class in derived class . obviously you need object oriented language to perform over riding as it is done between base and derived classes.

Overload a function with a derived class argument if you only have a pointer to the base class in C++

With double dispatch, it would be something like:

class Circle;
class Box;

// Overloaded functions (Defined elsewhere)
void ResolveCollision(Circle& a, Box& b);
void ResolveCollision(Circle& a, Circle& b);
void ResolveCollision(Box& a, Box& b);
class PhysicsObject // A pure virtual class
{
public:
virtual ~PhysicsObject() = default;

virtual void ResolveCollision(PhysicsObject&) = 0;
virtual void ResolveBoxCollision(Box&) = 0;
virtual void ResolveCircleCollision(Circle&) = 0;
};

class Circle : public PhysicsObject
{
public:
void ResolveCollision(PhysicsObject& other) override { return other.ResolveCircleCollision(*this); }
void ResolveBoxCollision(Box& box) override { ::ResolveCollision(*this, box);}
void ResolveCircleCollision(Circle& circle) override { ::ResolveCollision(*this, circle);}
// ...
};

class Box : public PhysicsObject
{
public:
void ResolveCollision(PhysicsObject& other) override { return other.ResolveBoxCollision(*this); }
void ResolveBoxCollision(Box& box) override { ::ResolveCollision(box, *this);}
void ResolveCircleCollision(Circle& circle) override { ::ResolveCollision(circle, *this);}
// ...
};

Hide, overload or overwrite in C++

Since foo is not virtual, the function called is based on the static type (i.e., the type the pointer is declared to point at) rather than the dynamic type (the type of object to which the pointer currently refers).

There are also some trickier cases to consider. One point (on which some of the other answers are actually somewhat misleading) is that it's not really just the function name that matters, but the entire function signature. For example:

#include <iostream>

struct base {
virtual void foo() {
std::cout << "base::foo";
}
};

struct derived : base {
virtual void foo() const {
std::cout << "derived::foo";
}
};

int main(){
base *b = new derived;

b->foo();
}

Here foo is qualified as virtual in both the base and (seemingly redundantly the) derived classes, but the call b->foo() still prints out base::foo.

The const added to the signature of derived::foo means it no longer matches the signature of base::foo, so instead of overriding the virtual function, we still end up with two separate functions with the same name, so derived::foo hides base::foo, but doesn't override it. Despite the virtual qualification, we get static binding, so b->foo(); invokes the base function rather than the derived, even though b points to an object of the derived type.

As Tony D pointed out in a comment, C++11 added a new wrinkle to the language to help ensure against this happening. When you want to override a base class function, you can add the identifier override to the function in the derived class:

struct derived : base {
virtual void foo() const override {
std::cout << "derived::foo";
}
};

With this, if there's a difference in function signature (as in the cases shown here), the compiler will produce an error message alerting you to the fact that derived::foo is marked as override, but doesn't actually override a function from the base class. This was, however, added in C++11, so if you're using an older compiler this feature may not be implemented (though thankfully, compilers that don't implement it are quickly fading into oblivion).

Correcting the signature in the base class to:

virtual void foo() const // ...

...will let the code compile, and produce the correct results.

C++ Design: Overloading/Overriding many many functions, way to clean up?

Unfortunately, what would solve your problem is a virtual template method, that is not possible.

Here is a more C-ish solution brought to the C++ world that can work around the limitation:

#include<unordered_map>
#include<functional>
#include<memory>
#include<iostream>
#include<utility>

struct BaseCommand {
static int counter;
};

int BaseCommand::counter = 0;

template<class T>
struct Command: BaseCommand {
static int type() {
static const int t = ++counter;
return t;
}
};

struct SpecificCommand1: Command<SpecificCommand1> {};
struct SpecificCommand2: Command<SpecificCommand2> {};

class Base {
struct Handler {
virtual void operator()(BaseCommand &cmd) = 0;
};

template<typename T>
struct THandler: Handler {
std::function<void(T)> func;
void operator()(BaseCommand &cmd) override {
func(static_cast<T&>(cmd));
}
};
protected:
template<typename T>
void assign(std::function<void(T)> f) {
auto handler = std::make_unique<THandler<T>>();
handler->func = f;
handlers[T::type()] = std::move(handler);
}

public:
template<typename Command>
void modifyCommand(Command cmd) {
auto it = handlers.find(Command::type());
if(it == handlers.end()) {
std::cout << "Modify command called with unimplemented command type: " << Command::type();
} else {
auto &h = *(it->second);
h(cmd);
}
}

private:
std::unordered_map<int, std::unique_ptr<Handler>> handlers;
};

class Derived: public Base {
public:
Derived() {
std::function<void(SpecificCommand1)> f =
[](SpecificCommand1) {
std::cout << "handler for SpecificCommand1" << std::endl;
};

assign(f);
}
};

int main() {
Base *b = new Derived;
b->modifyCommand(SpecificCommand1{});
b->modifyCommand(SpecificCommand2{});
}

The basic idea is to give a numeric type at runtime to your commands (it can be done with the CRTP idiom - see BaseCommand and the Command template class).

With this value accessible, it's a matter of creating a type-erased handler to deal with the commands for which you want to provide a specific implementation (see assign and Handler/THandler).

Once you have all the pieces correctly set, you have only to design and initialize those handlers in your derived classes. For it can be done using std::function, you can use as an handler a lambda, a public or private member method, a static method and so on.

See the constructor of Derived for further details.

Override and overload in C++

Overloading generally means that you have two or more functions in the same scope having the same name. The function that better matches the arguments when a call is made wins and is called. Important to note, as opposed to calling a virtual function, is that the function that's called is selected at compile time. It all depends on the static type of the argument. If you have an overload for B and one for D, and the argument is a reference to B, but it really points to a D object, then the overload for B is chosen in C++. That's called static dispatch as opposed to dynamic dispatch. You overload if you want to do the same as another function having the same name, but you want to do that for another argument type. Example:

void print(Foo const& f) {
// print a foo
}

void print(Bar const& bar) {
// print a bar
}

they both print their argument, so they are overloaded. But the first prints a foo, and the second prints a bar. If you have two functions that do different things, it's considered bad style when they have the same name, because that can lead to confusion about what will happen actually when calling the functions. Another usecase for overloading is when you have additional parameters for functions, but they just forward control to other functions:

void print(Foo & f, PrintAttributes b) { 
/* ... */
}

void print(Foo & f, std::string const& header, bool printBold) {
print(f, PrintAttributes(header, printBold));
}

That can be convenient for the caller, if the options that the overloads take are often used.

Overriding is something completely different. It doesn't compete with overloading. It means that if you have a virtual function in a base class, you can write a function with the same signature in the derived class. The function in the derived class overrides the function of the base. Sample:

struct base {
virtual void print() { cout << "base!"; }
}

struct derived: base {
virtual void print() { cout << "derived!"; }
}

Now, if you have an object and call the print member function, the print function of the derived is always called, because it overrides the one of the base. If the function print wasn't virtual, then the function in the derived wouldn't override the base function, but would merely hide it. Overriding can be useful if you have a function that accepts a base class, and every one that's derived from it:

void doit(base &b) {
// and sometimes, we want to print it
b.print();
}

Now, even though at compile time the compiler only knows that b is at least base, print of the derived class will be called. That's the point of virtual functions. Without them, the print function of the base would be called, and the one in the derived class wouldn't override it.



Related Topics



Leave a reply



Submit