tags:

views:

253

answers:

6

I was reading the C++0x FAQ by Stroustrup and got stuck with this code. Consider the following code

struct A
{
    void f(double)
    {
     std::cout << "in double" << std::endl;
    }
};

struct B : A
{
    void f(int)
    {
     std::cout << "in int" << std::endl;
    }
};


int main()
{
    A a; a.f(10.10);  // as expected, A.f will get called
    B b; b.f(10.10);  // This calls b.f and we lose the .10 here
    return 0;
}

My understanding was when a type is inherited, all protected and public members will be accessible from the derived class. But according to this example, it looks like I am wrong. I was expecting the b.f will call base classes f. I got the expected result by changing the derived class like

struct B : A
{
    using A::f;
    void f(int)
    {
     std::cout << "in int" << std::endl;
    }
};

Questions

  1. Why was it not working in the first code?
  2. Which section in the C++ standard describes all these scoping rules?
+2  A: 

Search for overload resolution. A similar, but not identical question.

Pontus Gagge
+4  A: 

The first code works as c++ is designed to work.

Overloading resolution follows a very complicated set of rules. From Stroustrup's c++ bible 15.2.2 "[A]mbiguities between functions from different base classes are not resolved based on argument types."

He goes on to explain the use of "using" as you have described.

This was a design decision in the language.

I tend to follow the Stroustrup book rather than the standard, but I'm sure it is in there.

[Edit]

Here it is (from the standard):

Chapter 13

When two or more different declarations are specified for a single name in the same scope, that name is said to be overloaded.

And then:

13.2 Declaration matching

1 Two function declarations of the same name refer to the same function if they are in the same scope and have equivalent parameter declarations (13.1). A function member of a derived class is not in the same scope as a function member of the same name in a base class.

morechilli
Would be worth adding the fixed example (ie. with using A::foo).
Richard Corden
+1  A: 

In C++, there is no overloading across scopes, scoped in derived classes are not an exception. (According to The C++ Programming Language)

For more info, check out http://www.research.att.com/~bs/bs_faq2.html#overloadderived

Silfverstrom
+1  A: 

In the first case, the base class method 'f' is hidden by the derived class method. In C++ there is no overloading across scopes; that is why it is not called. The C++ standard explains all the member name lookup rules in the section 10.2 Member name lookup [class.member.lookup]. HTH

Abhay
+5  A: 

Its because A::f is "hidden" rather than "overloaded" or "overridden". Refer:

http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9

aJ
+1  A: 

The first version of code should really call B::f. You re-define the symbol "f" in struct "B", so it hides the original symbol "f" from struct "A". It is not an overload, as it may seem.

Whenever compiler meets b.f(), it searches the "B" struct for a symbol "f". It is present there, so the compiler decides to call B::f(int), converting double to int. It sees no need to scan the parent class for a more suitable function...

Yet, when you add "using A::f", it is an explict directive for the compiler to scan a parent class for symbol "f". Now, B class has two overloaded functions: for int and for double.

I also believe, that you could write b.A::f() without using "using" directive in the original example...

SadSido