Reputation: 16640
I need explanation about why the following code does not compile. I have a workaround which I will articulate below, but I don't understand the failure of the original version.
To speed up code reading: The concept is to define an interface (ISomething
), then to create an abstract implementation (ASomething
) which implements the second function (2)
using the first (not yet defined) one (1)
. A complete implementation which derives from the abstract one (for example SomethingImpl
) must define the first method and has the option to override the second one.
#include <iostream>
class ISomething
{
public:
virtual ~ISomething()
{ }
virtual int f(int x) = 0; // (1)
virtual int f(int x, int y) = 0; // (2)
};
class ASomething
: public virtual ISomething
{
public:
virtual int f(int x, int y) // (2)
{
return f(x) + f(y); // (3)
}
};
class SomethingImpl
: public ASomething
{
public:
virtual int f(int x) // (1)
{
return x+1;
}
};
int main()
{
SomethingImpl a;
std::cout << a.f(10) << std::endl; // (1)
std::cout << a.f(10,20) << std::endl; // (2)
return 0;
}
Compiling this code gives error on both Visual Studio 2013 (Windows) and g++ 4.4.5 (Linux). The errors are very similar, I will detail the g++ output only:
$ g++ SibFun.cpp -o SibFun
SibFun.cpp: In member function ‘virtual int ASomething::f(int, int)’:
SibFun.cpp:18: error: no matching function for call to ‘ASomething::f(int&)’
SibFun.cpp:16: note: candidates are: virtual int ASomething::f(int, int)
SibFun.cpp:18: error: no matching function for call to ‘ASomething::f(int&)’
SibFun.cpp:16: note: candidates are: virtual int ASomething::f(int, int)
SibFun.cpp: In function ‘int main()’:
SibFun.cpp:36: error: no matching function for call to ‘SomethingImpl::f(int, int)’
SibFun.cpp:26: note: candidates are: virtual int SomethingImpl::f(int)
make: *** [SibFun] Error 1
I tried to use different notation at (3)
like return this->f(x) + this->f(y)
, but I experienced no significant change in the error message.
However when I changed (3)
to return ISomething::f(x) + ISomething::f(y);
I only got:
$ g++ SibFun.cpp -o SibFun
SibFun.cpp: In function ‘int main()’:
SibFun.cpp:36: error: no matching function for call to ‘SomethingImpl::f(int, int)’
SibFun.cpp:26: note: candidates are: virtual int SomethingImpl::f(int)
make: *** [SibFun] Error 1
But! When change (2)
from f
to g
all compiles and runs as expected.
What is the reason behind this begavior? Why can't I use the f
name for (2)
?
Upvotes: 1
Views: 115
Reputation:
The problem is not an 'overloading' problem, but hiding a base class function (See other answers)
A slightly modified example:
#include <iostream>
class ISomething
{
public:
virtual ~ISomething() {}
virtual int f(int x) = 0; // (1)
virtual int f(int x, int y) = 0; // (2)
};
class ASomething: public virtual ISomething
{
public:
virtual int f(int x, int y) // (2)
{
// `this->f(x)` fails:
ISomething& i = *this;
return i.f(x) + i.f(y); // (3)
}
};
class SomethingImpl: public ASomething
{
public:
virtual int f(int x) // (1)
{
return x+1;
}
};
int main()
{
SomethingImpl a;
// `a.f(10, 20)` fails:
ISomething& i = a;
std::cout << i.f(10) << std::endl; // (1)
std::cout << i.f(10, 20) << std::endl; // (2)
return 0;
}
Hence, calling f
from the interface, resolves the conflict. Although, you should consider using base::f
, as suggested in other answers.
Upvotes: 1
Reputation: 303517
Both compilation failures happen for the same reason. While you're overriding one virtual member function, you're hiding the other. In ASomething
:
virtual int f(int x, int y) // (2)
{
return f(x) + f(y); // (3)
}
Name lookup on f
finds ASomething::f
and stops, it doesn't keep going to look for other overloads. Since ASomething::f
takes two arguments, and you're trying to call it with one, error. In order to allow for overloading against the base class, you have to introduce the base class member functions with a using-declaration:
using ISomething::f; // NOW, ISomething::f(int ) is found by lookup
virtual int f(int x, int y)
{
return f(x) + f(y);
}
And similarly, SomethingImpl
needs a using ASomething::f;
statement so that a.f(10)
can compile.
Upvotes: 4
Reputation: 48487
Function overloading works only for functions visible in the same scope:
class ASomething
: public virtual ISomething
{
public:
virtual int f(int x, int y) // (2)
{
return f(x) + f(y); // (3)
}
using ISomething::f;
//~~~~~~~~~~~~~~~~~^
};
class SomethingImpl
: public ASomething
{
public:
virtual int f(int x) // (1)
{
return x+1;
}
using ASomething::f;
//~~~~~~~~~~~~~~~~~^
};
Upvotes: 7