2
struct A{
        void foo(A a){}
        virtual void foo(int c=1){}
};
struct B : public A{
        void foo(int c){}
};

int main(){
        A* object = new B();
        object->foo();
        ((B*)(object))->foo(*object);
}

Outputs:

test_test.cpp: In function ‘int main()’:
test_test.cpp:14:36: error: no matching function for call to ‘B::foo(A&)’
         ((B*)(object))->foo(*object);
                                    ^
test_test.cpp:8:14: note: candidate: virtual void B::foo(int)
         void foo(int c){}
              ^
test_test.cpp:8:14: note:   no known conversion for argument 1 from ‘A’ to ‘int’

Though i'm able to still use A::foo via ((B*)object)->A::foo(*object) i would like to hear the story behind why it is behaving like that.

user1079475
  • 379
  • 1
  • 5
  • 17
  • 1
    That kind of what "hiding" *means*. Also, another way around the hiding is with the `using` keyword, like e.g. `using A::foo;` inside the `B` class definition. – Some programmer dude Sep 27 '17 at 13:30

2 Answers2

3

i would like to hear the story behind why it is behaving like that.

Because this is the rule of name lookup. If the name is found at the current scope (e.g. the class B), the name lookup stops, the further outer scope (e.g. the class A) won't be examined. The process of name lookup would not consider the parameters of the functioin, but only the names.

After the name lookup overload resolution is performed based on the names found, then you got the error showed.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • I'm still not convinced why it shouldn't nest the lookup down the chain. By which i mean why someone decided that this is how it should stay. What pitfalls made it to live it up to current standard – user1079475 Sep 27 '17 at 13:39
  • @user1079475 Suppose you call the member function `foo` in another member function of `B`, like `foo(0);`, and sb defined a global `foo(int)` too. Now you have to tell the compiler which one you want invoke; the one of `B`, or `A`, or the global one. – songyuanyao Sep 27 '17 at 13:44
  • I don't think that is a part of the issue because it just goes with B::foo(int) – user1079475 Sep 27 '17 at 14:10
  • @user1079475 Suppose you have a member function `foo(int)` and calling it as `foo('c');` in another member function. You're passing a `char` to it but you're sure and this is your intent, `char` will be converted to `int`. Then sb add a globle `foo(char)`; you won't get any compile error or warning but you'll find the behavior changed. A kind of *surprise*. Anyway, it's just a sort of tradeoff of design. – songyuanyao Sep 27 '17 at 14:19
  • Yes i'm familiar with this ambiguity and i know that it is still there for example in try catch sections. This is the one of the reasons i don't understand why it does not work the same in this case since we are already dealing with such problems in c++ – user1079475 Sep 27 '17 at 15:22
2

The short answer is 'because that's what the rules say'.

You can achieve what you want like this:

struct A{
        void foo(A a){}
        virtual void foo(int c=1){}
};
struct B : public A{
        using A::foo;
        void foo(int c){}
};

int main(){
        A* object = new B();
        object->foo();
        ((B*)(object))->foo(*object);
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142