C++ inheritance and function overloading
Here is a simple looking C++ program, which has two classes A and B ( which derives from A ). A has a function fun() which B tries to overload as fun(int). Sounds simple and the program looks correct but it doesn’t compile. Have a look at http://codepad.org/NQ3JNuRr .
Its hard to digest for it is an obvious code to compile in C++. The code listing is as below:
#include<iostream>
using namespace std;
class A{
public:
void fun(){cout<<"fun\n";}
};
class B: public A{
void fun(int i){cout<<"funB\n";}
};
int main()
{
B b;
b.fun();
}
- This typical case has two work-arounds:
- One is ‘using A::fun’ inside class B : http://codepad.org/RnCIBBuO
- Other is calling as ‘b.A::fun()’ inside function main().
It looked like to puzzle to me, but its clearly mentioned in section “13.2 – Declaration matching” from the C++ International Standard ( which can be found here http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf ) and I quote:
Two function declarations of the same name refer to the same function if they are in the same scope and have equivalent
parameter declarations (13.1). A function member of a derived class is not in the same scope as a function member of
the same name in a base class.Example:
class B { public : int f ( int ); }; class D : public B { public : int f ( char *); };Here D::f(char*) hides B::f(int) rather than overloading it.
void h ( D * pd ) { pd - > f (1); // error: // D::f(char*) hides B::f(int) pd - > B :: f (1); // OK pd - > f ( " Ben " ); // OK, calls D::f }
Its all a problem with getting the scope of functions correct. So when we chose ‘using A::fun’ inside class B, we bring the function A::fun in same scope as of B::fun(int). When we call the function as ‘b.A::fun()’, we clearly specify to the compiler that we want to use fun() from class A’s scope. That way the compiler will know how to resolve the function names. This is simply because the standard says so. I wonder whether there is sufficient RTTI data which can be used to avoid specifying scope when coding for such a case, so that the function resoultion could be deferred til the runtime. At the run-time the function signature resolution could be done upwards in the class hierarchy. What could be the performance implication in doing so?
asif 11:58 pm on July 17, 2010 Permalink |
C++ exposes functions if not overloaded without any problem so i think its a explicit design decision to hide the base class functions in case of overload. but i cant see any benefit out of this.
Somewhere i read :
“if you change the function signature or return type then you are actually changing the interface of the base class. If this is what you have intended to do then you are using inheritance primarily to reuse code, and not to maintain the common interface of the base class (which is an essential aspect of polymorphism). In general, when you use inheritance this way it means you’re taking a general-purpose class and specializing it for a particular need – which is usually, but not always, considered the realm of composition.”
this is absolutely shitty reason.Then why C++ does not hide names if i add a completely new function coz that also means im changing the interface.
C++ has too way many gotchas ….
tuxdna 1:47 pm on July 20, 2010 Permalink |
I am closer to what you feel. Even I think that hiding the function makes us write more code when the compiler apparently could do that job for us. All I could conclude is that the “Standard says so”, but why? What was the rational behind this decision?
asmcoder 8:28 am on August 6, 2010 Permalink |
This is probably a design bug in the language. They simply haven’t thought well enough.
Well designed languages have keyword “override” for this and the problem does not exist there.
Stephen Shaw 12:29 am on July 18, 2010 Permalink |
We just covered this stuff in the class that I’m taking on C++. The professor has some really good slides about OOP – http://uvu.freshsources.com/page1/page9/page19/page19.html
tuxdna 1:45 pm on July 20, 2010 Permalink |
@Stephen
I found the slide 29 of OOP ( 3370-OOP.ppt ) from the link you gave. It talks about “Object Slicing” that happens when we pass an object of derived class when the function accepts base class as well ( which makes it legal ). I found that slide a bit confusing though. Does it mean that we should always pass objects as reference ( or maybe a pointer ) in such a case?
asif 6:29 pm on July 27, 2010 Permalink
Object Slicing is entirely different concept ….
Jason Merrill 4:27 am on July 18, 2010 Permalink |
There’s no reason to bring RTTI into the picture, as we know statically that A is a base of B. This is just how C++ lookup rules work: any declaration of fun in B hides all the declarations in A rather than overloading them. Adding the ‘using’ is the right way to deal with this. -Woverloaded-virtual will warn about this in some cases.
asif 1:55 pm on July 27, 2010 Permalink |
@Jason
Correct RTTI does not comes into picture. Anything which fails at compile time is not at all related to RTTI.