6

Please look at the following code:

#include <iostream>
using namespace std;

class A {
  public:
    A() {};    
    virtual void foo(double d) { cout << d << endl; }
    virtual void foo(double d, int a) = 0;
  };

class B : public A {
  public: 
    B() {};
    virtual void foo(double d, int a) { cout << d << endl << a << endl; }  
  };

int main()
  {
  B b;
  b.foo(3.14);
  return 0;
  }

The compiler (tried g++ and visual c++ 2008) says that there's no function like B:foo(double). The exact message of g++ is:

main.cpp:21: error: no matching function for call to ‘B::foo(double)’

It looks like the effect of hiding rule, but in my opinion the rule should not be used here, since I'm not overriding foo(double) and both foo methods are defined in base class.

I know that I can fix the problem with

using A::foo;

declaration in the derived class B.

Can you explain why the code does not compile and what rules of C++ apply here?

Wacek
  • 4,326
  • 2
  • 19
  • 28
  • 1
    This is just the "name hiding" issue. Why can't you just use the `using A::foo` clause ? – ereOn Jul 05 '10 at 07:56
  • Not an exact duplicate, but same issue discussed here: http://stackoverflow.com/questions/72010/c-overload-resolution – ereOn Jul 05 '10 at 08:00
  • In this case if you want to implement your pure virtual foo method you MUST redefine all the methods with name `foo` or choose different names for pure virtual methods and implemented methods. – Sergey Jul 05 '10 at 08:56
  • Hey, you don't need to specify that foo(double, int) in B is virtual. – rkellerm Jul 05 '10 at 09:27

4 Answers4

6

The hiding rule is not about overriding, it is about hiding of names. If the derived class declares a member function, this hides other base class member functions with the same name. This also happens in your case.

sth
  • 222,467
  • 53
  • 283
  • 367
5

Names shadow, not specific functions. Once you make a foo in B, all base foo's (note, by name!) are shadowed.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
2

When the compiler encounters an identifier, the lookup rules kick in and start searching for that identifier. In your concrete situation, with b.foo, the compiler knows that foo must be a member of B or one of its subclasses. The lookup rules state that the compiler must start with the most derived class (considering the static type of the object) and follow up in the hierarchy, and that once the identifier is found in one level only definitions in that level will be considered, it must not keep looking upwards.

B& f(); // might return a B or something derived from B
void test() {
   B& b = f(); // static type is B
   b.foo(1.0);
}

Regardless of what f returns, the static type is B, so the compiler will lookup in B class and find B::foo(double,int). Since there is no other foo declaration at that level, the compiler must try to match (and fail) the function call with the available method declarations.

The important thing is that the lookup does not look the object but rather looks by type and going upwards, cutting as soon as it encounters the first instance.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
1

Looks perfectly reasonable to me. Although function signature does matter to know what the function is, I can see how this behavior prevents very stupid mistakes.

As ereOn suggested, using directive would be a fair price to pay.

Pavel Radzivilovsky
  • 18,794
  • 5
  • 57
  • 67
  • +1: If you want to learn more, you can take a look at http://becomeaprogrammerin21years.blogspot.com/2008/03/c-inheritance-oddity.html – ereOn Jul 05 '10 at 08:02