Interesting virtual function problem.
I can't believe I never ran into this problem before.
Code:
struct first
{
virtual int function(int a, int b)
{
/* whatever */
}
virtual int function(int a)
{
return function(a, 0);
}
virtual int function(void)
{
return function(0);
}
};
struct second : first
{
void stuff()
{
/* whatever */
}
virtual int function(int a, int b)
{
stuff();
return first::function(a, b);
}
};
int main()
{
second obj;
return obj.function();
}
At this point, the compiler complains that 'struct second' has no function with that signature, because I overided one of the functions having the same name. Stupid. Any compiler worth it's salt should be able to sort that out!
Anyway, so what's to do? Redefine each function? Then I came up with a work-around, though it's a bit of a hack, and demands a new discipline altogether.
The function with the most parameters is the 'lowest common denominator' (LCD) (since all others ultimately call that one internally). So here's what I did:
Code:
struct first
{
virtual int lcd_function(int a, int b)
{
/* whatever */
}
virtual int function(int a, int b)
{
return lcd_function(a, b);
}
virtual int function(int a)
{
return function(a, 0);
}
virtual int function(void)
{
return function(0);
}
};
struct second : first
{
void stuff()
{
/* whatever */
}
virtual int lcd_function(int a, int b)
{
stuff();
return first::lcd_function(a, b);
}
};
int main()
{
second obj;
return obj.function();
}
Voila.
OK, so if anyone can come up with a better solution - please let me know. I'm glad it works, on the one hand, but disappointed that I may have to incorporate this feature into future code!
Any suggestions are welcome.
Re: Interesting virtual function problem.
Quote:
Originally posted by Sebastiani
At this point, the compiler complains that 'struct second' has no function with that signature, because I overided one of the functions having the same name. Stupid. Any compiler worth it's salt should be able to sort that out!
It's not the compiler's fault; this is the way name resolution works in C++; making it work in any other means would be more problematic. The most restricted scope is searched first, then the next, etc. Once a match is found for the name, even a match that is incorrect in the context of the statement, no further scopes are checked. This is a Good Thing; there could be some very nasty problems if C++ compilers tried to use definitions that fit better but were in a more distant scope.
For an example of how C++ resolves, say I had this:
Code:
namespace a{
namespace b{
class A{
/*...*/
};
class B : public A{
void something(){
x(4);
}
}
}
}
When that line "x(4)" is being parsed, the compiler must resolve the name "x" into a variable/function name. So it starts at the most restrictive scope and works its way out.
Assuming something() doesn't have any further nested scopes, it would first check to see if x was declared in something(). After that, it would search the class B, then the class A, then the namespace b, then the namespace a, then the global namespace.
Whenever it finds at least one match, it goes no further. It looks at all the definitions of x at that level, and chooses the best of those.
In your case, there is a name match within class second. "first" never participates in the name resolution, because at least one match is found in "second", which is a more qualified namespace than "first".
However, you can fix your struct to get the effect you want. C++ provides a method to treat one or more names from one scope as if they were in a different scope. It's often, IMO, abused, but this is one of those great times to use it (pun intended). The change you need is as follows:
Code:
struct second : first
{
void stuff()
{
/* whatever */
}
using first::function;
virtual int function(int a, int b)
{
stuff();
return first::function(a, b);
}
};
This makes all of a's copies of "function" participate in the name resolution.
Do note, this is "all or nothing" -- you get all of first's copies of function(), or none of them. You can't get first::function(void) but not first::function(int). This would be incorrect anyway; name resolution happens before signature matching, so signatures don't affect name resolution.