Reputation: 55
I have the following code:
struct CommonVariables
{/*some common variables that need to be proceed*/};
struct CommonHandler
{
static void foo(const CommonVariables& vars) {/*processed vars*/}
void bar(const CommonVariables& vars) {/*processed vars*/}
};
struct AnotherVariables
{/*another variables*/};
struct AnotherHandler
{
static void foo(const AnotherVariables& vars) {/*processed vars*/}
void bar(const AnotherVariables& vars) {/*processed vars*/}
};
struct Derived : CommonHandler, AnotherHandler
{};
And when I try to call Derived::foo(/any variable type/) or Derived d; d.bar(/any variable type/), the compiler gives me an error: "reference to 'foo(or bar)' is ambiguous".
Yet below I have almost the same situation:
struct DifferentHandler
{
static void foo(const CommonVariables& vars) {}
static void foo(const AnotherVariables& vars) {}
void bar(const AnotherVariables& vars) {}
void bar(const CommonVariables& vars) {}
};
And calling DifferentHandler::foo(/any variable type/) or 'bar' works just fine.
There are plenty of solutions to work around the first code block (template traits, etc.). What I specifically want is to overload methods through inheritance. And I don't understand why calls from Derived are ambiguous (since input parameters have different types, from compiler point of view those functions are different. Like in DifferentHandler)
NOTE: I've tried MinGW5.8 (in Qt Creator), and MSVC2015 in VS2015. Both compilers generated same error.
Upvotes: 2
Views: 2148
Reputation: 16824
In C++, if a member function of a derived class has the same name as a member function of a base class, then the derived class's version hides the base version -- even if the function signatures are different, and you would otherwise expect them to overload. (If the base class member function is virtual, then the derived class's signature must match exactly*, or it will (usually unintentionally) hide the base class's version -- this is the reason C++11 added the override
psuedo-keyword).
For example:
struct base {
void foo(std::string s) {}
};
struct derived : base {
void foo(int i) {}
};
int main() {
derived d;
d.foo("hello"); // Error -- cannot convert const char* to int
}
The solution is to use a using
directive to bring the base class's member function into the derived class scope, i.e.
struct derived : base {
using base::foo;
void foo(int i) {}
};
(An alternative is to use the obscure
derived d;
d.base::foo("hello"); // works
syntax to specify that you want to call the base class version, but this is rarely seen in the real world.)
Upvotes: 2
Reputation: 62563
Here you go:
struct Derived : CommonHandler, AnotherHandler
{
using CommonHandler::foo;
using CommonHandler::bar;
using AnotherHandler::foo;
using AnotherHandler::bar;
};
Fixes your problem.
The reason for original code not working is found in C++ standard. Here are interesting quotes:
In 10/2:
The base class members are said to be inherited by the derived class. Inherited members can be referred to in expressions in the same manner as other members of the derived class, unless their names are hidden or ambiguous (10.2).
Continuing reading to 10.2:
Member name lookup determines the meaning of a name (id-expression) in a class scope (3.3.7). Name lookup can result in an ambiguity, in which case the program is ill-formed....
...consists of two component sets: the declaration set, a set of members named f...
If the name of an overloaded function is unambiguously found, overloading resolution (13.3) also takes place before access control
Basically, it goes by name first and applies resolution later. Introducing them to derived class through using
declaration puts them all in the scope of derived class, where normal resolution rules kick-in.
Upvotes: 6