c++ overload method argument with original method's argument derived class - c++

I have the following objects
#include <stdio.h>
class foo_t{ };
class bar_t: public foo_t{ };
class zoo_t: public bar_t{ };
class base_t{
public:
void dostuff(foo_t * foo){ printf("Defaulting to base\n"); };
};
class derived_t: public base_t{
public:
void dostuff(bar_t * bar){ printf("Overloading with derived\n"); };
};
int main(){
derived_t derived;
zoo_t zoo;
derived.dostuff(&zoo);
}
I see it is doing what I mean, but I would like you to confirm that this is not just a coincidence.
What I mean is that I want C++ to resolve the method that "gets closer" to the specialized class zoo_t. In this case the first ancestor found is bar_t which determines that the derived_t class method is invoked. Is this the way C++ resolves overloaded methods when arguments are both specialized and base classes?

First off, I see your functions are not virtual. I will assume that's intended and leave virtual out of discussion.
You normally don't overload a base class's member functions in a derived class; you hide them instead. Which means that base_t::dostuff is not accessible through an object-accessing expression of type derived_t. In other words, this won't compile:
int main()
{
derived_t derived;
foo_t foo;
derived.dostuff(&foo);
}
However, this will:
int main()
{
derived_t derived;
foo_t foo;
base_t& base = derived;
base.dostuff(&foo);
derived.base_t::dostuff(&foo);
}
This has other implications as well. For example the code below will print Defaulting to base:
int main()
{
derived_t derived;
zoo_t zoo;
base_t& base = derived;
base.dostuff(&zoo);
}
To summarize - which function gets called is based on the type of the expression choosing the object (the expression to the left of . or ->), and that type only. That will always work that way, so if that's the behaviour you're after, you're fine.
If you want to really overload the inherited function instead of hiding it, you can use a using declaration:
class derived_t: public base_t{
public:
void dostuff(bar_t * bar){ printf("Overloading with derived\n"); };
using bas_t::dostuff;
};
Then, the following code will work:
int main()
{
derived_t derived;
foo_t foo;
bar_t bar;
zoo_t zoo;
derived.dostuff(&foo); // calls base
derived.dostuff(&bar); // calls derived
derived.dostuff(&zoo); // calss derived
}
Live example

Related

C++ public base class function is inaccessible from derived class [duplicate]

recently i came to know this - if a derived class redefines base class member method(s) then all the base class methods with same name become hidden in derived class.
#include<iostream>
using namespace std;
class Base
{
public:
int fun()
{
cout<<"Base::fun() called";
}
int fun(int i)
{
cout<<"Base::fun(int i) called";
}
};
class Derived: public Base
{
public:
int fun()
{
cout<<"Derived::fun() called";
}
};
int main()
{
Derived d;
d.fun(5); // Compiler Error
return 0;
}
Error :
In function 'int main()':
Line 30: error: no matching function for call to 'Derived::fun(int)'
compilation terminated due to -Wfatal-errors.
but just wanna know the reason behind it? why is it not calling fun(int i) method of Base Class since Derived class is derived from Base
The fundamental reason is to make code more robust.
struct Base {
};
struct Derived : Base {
void f(long);
void g() { f(3); } // calls Derived::f
}
Now suppose Base is defined in a library, and you get an update to that library and the update changes the definition of Base:
struct Base {
void f(int);
};
Now suppose that searches for overloaded functions didn't stop when a name was found. In that case, Derived::g would call Base::f instead of Derived::f, and your derived class would quietly do something completely different from what it did before, and different from what it was designed and documented to do.
You've already discovered that derived-class overloads will shadow (prevent the visibility of) base-class methods by the same name but different parameters. Let's just claim this was done for some historical or perceived safety reason, and look at a fix:
class Derived: public Base
{
public:
using Base::fun; // expose the base-class method
int fun()
{
cout<<"Derived::fun() called";
}
};

Cast function pointers that differs by argument type

Why this is not legal:
class Base
{
public:
Base(){};
virtual ~Base(){};
};
class Derived : public Base{};
void takeDerived(Derived * c){};
// main
void(*ptr)(Base*) = static_cast<void(*)(Base*)>(&takeDerived); // doesn't work
// but this work ok, as well as reinterpret_cast
// void(*ptr)(Base*) = (void(*)(Base*))(&takeDerived);
Derived is a Base. Why can't it be casted in function parameter? For example, I can do this easily even without casting:
void takeBase(Base* c){};
takeBase(new Derived{});
It's just designed to be that way. A Base isn't a Derived. The is-a relationship for class derivation can't be reversed.
The type of a function parameter means "accept", while the type of an object means "fit". Casting the type of a function changes what it accepts. It's dangerous to allow a function to accept whatever isn't what it originally accepts.
Consider this code:
class Base {};
class Derived : public Base {
public:
int t;
void useDerived() {}
};
void useDerived(Derived *d){
d->useDerived();
}
What should happen if a Base object is passed?
Base b;
((void(*)(Base*))useDerived) (&b);
Even worse, what if another derivation of Base is passed?
class AnotherDerived : public Base {
public:
double t;
void useDerived() {}
};
AnotherDerived ad;
((void(*)(Base*))useDerived) (&ad);
Yes, but you're trying to do it the other way around. You cannot do
void takeDerived(Derived *c) { }
...
Base b;
takeDerived(&b);
The function pointer cast you're trying to do would enable these shenanigans; you could do
void (*ptr)(Base*) = takeDerived;
Base b;
ptr(&b); // Oops.
Then things would explode, and that would be bad.

Function overriding in C++ works without 'virtual'

I have a class that contains some functions (none are virtual) and 2 more classes publicly inherit that class. In both the sub classes I override the same function of the base class.
After creating objects of all three classes in main (located at the same file), I call the original function with the baseclass object and the overridden functions with the derivedclass objects.
I was expecting all 3 function calls to run the original function from the base class (since I didn't use 'virtual' anywhere in the code), but I actually get each version of that function working according to the class in which it was defined (3 different versions).
I have the classes Base & Derived as follows:
struct Base
{
void foo();
};
struct Derived : Base
{
void foo();
};
in main:
int main()
{
Derived d;
d.foo();
}
I thought d.foo() should run Base::foo() if not using 'virtual'.
This is not "overriding"... and it doesn't need to be.
struct Base
{
void foo();
};
struct Derived : Base
{
void foo();
};
int main()
{
Derived d;
d.foo();
}
If I understand you correctly, then you were expecting this to execute Base::foo(), because the functions are not virtual and therefore one does not override the other.
But, here, you do not need virtual dispatch: the rules of inheritance simply state that you'll get the right function for the type of the object you run it on.
When you need virtual dispatch/overriding is a slightly different case: it's when you use indirection:
int main()
{
Base* ptr = new Derived();
ptr->foo();
delete ptr;
}
In the above snippet, the result will be that Base::foo() is called, because the expression ptr->foo() doesn't know that *ptr is really a Derived. All it knows is that ptr is a Base*.
This is where adding virtual (and, in doing so, making the one function override the other) makes magic happen.
You cannot override something that isn't virtual. Non-virtual member functions are dispatched statically based on the type of the instance object.
You could cheat by "overriding" a function by making it an inline function calling something indirectly. Something like (in C++03)
class Foo;
typedef int foo_sig_t (Foo&, std::string&);
class Foo {
foo_sig_t *funptr;
public:
int do_fun(std::string&s) { return funptr(*this,s); }
Foo (foo_sig_t* fun): funptr(fun) {};
~Foo () { funptr= NULL; };
// etc
};
class Bar : public Foo {
static int barfun(Bar&, std::string& s) {
std::cout << s << std::endl;
return (int) s.size();
};
public:
Bar () : Foo(reinterpret_cast<foo_sig_t*>)(&barfun)) {};
// etc...
};
and later:
Bar b;
int x=b.do_fun("hello");
Officially this is not overloading a virtual function, but it looks very close to one. However, in my above Foo example each Foo instance has its own funptr, which is not necessarily shared by a class. But all Bar instances share the same funptr pointing to the same barfun.
BTW, using C++11 lambda anonymous functions (internally implemented as closures), that would be simpler and shorter.
Of course, virtual functions are in generally in fact implemented by a similar mechanism: objects (with some virtual stuff) implicitly start with a hidden field (perhaps "named" _vptr) giving the vtable (or virtual method table).

Hiding of all overloaded methods in base class

recently i came to know this - if a derived class redefines base class member method(s) then all the base class methods with same name become hidden in derived class.
#include<iostream>
using namespace std;
class Base
{
public:
int fun()
{
cout<<"Base::fun() called";
}
int fun(int i)
{
cout<<"Base::fun(int i) called";
}
};
class Derived: public Base
{
public:
int fun()
{
cout<<"Derived::fun() called";
}
};
int main()
{
Derived d;
d.fun(5); // Compiler Error
return 0;
}
Error :
In function 'int main()':
Line 30: error: no matching function for call to 'Derived::fun(int)'
compilation terminated due to -Wfatal-errors.
but just wanna know the reason behind it? why is it not calling fun(int i) method of Base Class since Derived class is derived from Base
The fundamental reason is to make code more robust.
struct Base {
};
struct Derived : Base {
void f(long);
void g() { f(3); } // calls Derived::f
}
Now suppose Base is defined in a library, and you get an update to that library and the update changes the definition of Base:
struct Base {
void f(int);
};
Now suppose that searches for overloaded functions didn't stop when a name was found. In that case, Derived::g would call Base::f instead of Derived::f, and your derived class would quietly do something completely different from what it did before, and different from what it was designed and documented to do.
You've already discovered that derived-class overloads will shadow (prevent the visibility of) base-class methods by the same name but different parameters. Let's just claim this was done for some historical or perceived safety reason, and look at a fix:
class Derived: public Base
{
public:
using Base::fun; // expose the base-class method
int fun()
{
cout<<"Derived::fun() called";
}
};

Overriding functions that takes inherited structures

struct struct1
{};
struct struct2:public struct1
{};
class Base
{
public:
virtual void foo(struct1 *s)
{
cout<<"foo in Base"<<endl;
}
};
class Der:public Base
{
public:
virtual void foo(struct2 *s)
{
cout<<"Foo in Der"<<endl;
}
};
int main()
{
struct2 s;
Base *b = new Der();
b->foo(&s);
}
When I call the function in main It calls the member in Base."foo in Base" gets printed. It prints "foo in Der" when the Derived class function takes struct1 pointer. But Is there any way to make it take struct2 pointer and display "foo in Der"
What you are asking for, interpreting that you mean to override the behavior of Base::foo, would be co-variant arguments to the function, and that is not possible in OO, as the derived type would be narrowing the contract of the base type, and thus it would break the Liskov Substitution Principle. You would not be able to substitute an object of type Base with an object of type Der, as the latter does not accept a struct1 object that is not a struct2 object.
When the derived type function has the same signature (i.e. also takes a struct1*), then it overrides the behavior of the Base and dynamic dispatch kicks in. But when you the signature has struct2* it does not override but rather hides the Base function.