9

Why in the next program the member function foo has priority over the global foo although the global one match the type?

#include <iostream>
using namespace std;

void foo(double val) { cout << "double\n";}

class obj {
public:
  void callFoo() { foo(6.4); }
private:
  void foo(int val) {cout << "class member foo\n"; }
};

int main() { 
  obj o;
  o.callFoo();
}
user890739
  • 702
  • 1
  • 13
  • 33

6 Answers6

9

Because the member function named foo could be found at the class scope, and then name lookup will stop, so the global version foo won't be considered for overload resolution, even if the global version is more appropriate here. It is a kind of name hiding.

If you want to call the global version, you could explicitly call it by ::foo(6.4);.

And here is a workaround to bring the global function into overload resolution.

Reference for Unqualified name lookup

Community
  • 1
  • 1
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
9

Consider what would happen if a global function declared somewhere in your code base (possibly several #include statements away) would trump an class obj member function declared right there in the class itself...

It would mean that, if you want to play it safe, you would have to fully qualify every single call to a member function...

this->foo();

...instead of having to qualify the less likely case of actually referring to the global function.

::foo();

This is called the "concept of least surprise".

DevSolar
  • 67,862
  • 21
  • 134
  • 209
  • 2
    Thanks for accepting this answer. However, @songyuanyao is *technically* more correct, and got further references. – DevSolar Sep 16 '14 at 08:58
  • Yeah, imagine the horror of having to qualify every call to a class method... *I'm looking at you, Python.* – skrrgwasme Sep 24 '14 at 22:55
3

One of the tenets of method overloading is that the specific should trump the general. In your example, the member method will always be more specific than a global method.

llogiq
  • 13,815
  • 8
  • 40
  • 72
3

In general, when scopes are nested, any name declared in the inner scope hides any entities with the same name in an outer scope when that name is used in the inner scope. So, in this case, when used in the class scope, names declared in the class will hide those declared in the enclosing namespace.

The outer name is still available if you qualify it; in this case, being in the global namespace, it's available as ::foo.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
1

You could think of it as increasing "specialisation" as you move from the global namespace through any nested namespaces around your class, nested classes etc. down to the member functions involved. If you say "foo" in this inner context, a more "specialised" foo can be expected to be more relevant to the caller. Further, if the global one was used preferentially, then someone adding symbols to a less "specialised" scope could break a class that defined a same-named symbol, undoing a lot of the benefits of namespaces and identifier scoping. The basic idea is that your class has a lot of freedom to use meaningful but concise identifiers - which may well be used by other code in your application - but it's only when a meaning for that identifier isn't available in the most local scope that it starts looking further and further afield.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
1

In terms of priority for scope resolution (default) when using same name of an identifier, local scope, member of class (class scope), global scope

Dr. Debasish Jana
  • 6,980
  • 4
  • 30
  • 69