5

In this thread the author of the accepted answer explains why the overridden method in the derived class can not be resolved by the compiler. However the example is relative to a type cast resolution, that is both the base and derived overloaded method have one parameter only and the ambiguity is limited to that parameter type.

But where is the ambiguity when the overloaded methods have a different number of parameters, like in this example?

Note that I'm not asking why the example produces a compile error, I'm asking why the language was designed this way.

#include <iostream>
using namespace std;

class A
{
public:
   inline int f(int x) { return x; }
};

class B: public A
{
public:
   inline int f(int x, int y) { return x+y; }
};


int main()
{
  B b;

  cout << b.f(1) << endl; // COMPILE ERROR
  cout << b.f(1,2) << endl;
}
Community
  • 1
  • 1
Robert Kubrick
  • 8,413
  • 13
  • 59
  • 91
  • There is no ambiguity here. Ambiguity is when multiple considered functions are equally compatible with the function call. In this case, only `B::f` is considered; `A::f` is hidden by it. – M.M May 12 '14 at 21:45
  • 3
    Just a guess: default-arguments? wouldn't `f(int x, int y = 0)` create a mess like the one explained in the linked answer? – alain May 12 '14 at 22:08

4 Answers4

1

The reason you get a compiler error is that f from class A is hidden by the f in class B.

When the compiler does member name lookup, it uses base classes only if the name is not found in the object's class, so it doesn't matter if you have a member in a base class that has a proper parameter list for your call.

From the standard:

10.2.5 Otherwise (i.e., C does not contain a declaration of f or the resulting declaration set is empty), S(f, C) is initially empty. If C has base classes, calculate the lookup set for f in each direct base class subobject Bi , and merge each such lookup set S(f, Bi) in turn into S(f, C).

imreal
  • 10,178
  • 2
  • 32
  • 48
1

In C++, name lookup will stop looking for other names as soon as it find the requested name in one of the base classes. In your case, the name f is defined in B, so the compiler stop looking in the other base classes. You can make A::f visible with a using declaration :

class B: public A
{
 public:
  using A::f;
  int f(int x, int y) { return x+y; }
};
el aurens
  • 361
  • 1
  • 5
  • This does not answer the author's question. – R Sahu May 12 '14 at 21:50
  • The first part of my answer explains (briefly) how names hiding works in C++. Would you explain to me why this doesn't answer author's question ? – el aurens May 12 '14 at 21:52
  • @RSahu Thanks! After 3 answers all repeating the same thing I thought the question wasn't clear enough. – Robert Kubrick May 12 '14 at 21:53
  • @elaurens Read the question part in bold. – Robert Kubrick May 12 '14 at 21:53
  • @RobertKubrick Unless someone from standardisation committee answers, I think we can only speculate. The standard is clear about this feature (https://github.com/cplusplus/draft/blob/master/papers/N3797.pdf?raw=true) section 10.2. My 2cts – el aurens May 12 '14 at 22:17
0

The compiler will look for the implementation of function f in class B. The compiler found such an implementation, which has two arguments. You provided only one argument, so there is your error.

PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
  • 1
    I know what's happening, I'm asking why the language was designed to prevent a base class lookup when the number of parameters is different. – Robert Kubrick May 12 '14 at 21:44
  • 1
    @RobertKubrick it's nothing to do with number of parameters ; the symbol `f` exists in `B`, so it is not looked up in `A` by default. `f` could be a variable and the same thing happens – M.M May 12 '14 at 21:47
0

How would you take away overloads that make no sense in a derived class? Even in your example, assume that if you have a B instance, you wanted to forbid the use of the single-parameter function. As it is written now, you've removed the single-parameter version (well, at least removed it from name resolution in the context of a B instance). But if you wanted to still have that version available, you can specify using A::F; in your class to bring in the single-parameter version.

Andre Kostur
  • 770
  • 1
  • 6
  • 15