Changgong  Zhang
Changgong Zhang

Reputation: 177

effects of using declaration on name lookup for two exactly same names

Basically, my question is related to name lookup and using declaration (http://en.cppreference.com/w/cpp/language/namespace).
Suppose we have the following (definitely stupid) codes:

class Base { 
public:
    void fun()
    {std::cout << "Base fun" << std::endl;}
};

class Derived : public Base { 
public:
    // Here both names "fun" are visible or not?
    using Base::fun;//let's call this func_1

    void fun() //let's call this func_2
    {
        std::cout << "Derived fun" << std::endl;
    }
};

Derived d;
d.fun(); // This resolves to func_2, why?

Therefore, my understand is now we should have both names visible, and then for name lookup, there should be some ambiguity. But actually it is not. What is the reason or in other words, do I misunderstand some concepts?

Upvotes: 0

Views: 246

Answers (2)

txtechhelp
txtechhelp

Reputation: 6777

The link you're referencing is for namespace's, you should instead refer to the class using-declaration where it states:

If the derived class already has a member with the same name, parameter list, and qualifications, the derived class member hides or overrides (doesn't conflict with) the member that is introduced from the base class.

In the case of your posted code, void fun() in Base is hidden by void fun() in Derived, so no, they're not both "visible", unless you are explicit when you call fun, example:

class Base { 
    public:
        void fun() { std::cout << "base" << std::endl; }
};

class Derived : public Base { 
    public:
        using Base::fun;
        void fun() { std::cout << "derived" << std::endl; }
};

Derived d;
d.fun(); // name lookup calls Derived::fun
d.Base::fun(); // explicitly call Base::fun

Additionally, since you've publicly derived from Base, strictly speaking, you don't need the using declaration; you would in the instance that void fun() were protected in Base or you private/protected'ly inherited from Base, example:

#include <iostream>

class Base {
    public:
        void fun() { std::cout << "base" << std::endl; }
    protected:
        void fun2() { std::cout << "base2" << std::endl; }
};

// class default is private
class Private : Base {
    public:
        // fun() won't be accessible since private inheritance and no using
        // fun2 can now be accessed directly
        using Base::fun2;
};

class Public : public Base {
    public:
        // fun is already public
        using Base::fun2; // bring into scope
};

class Derived : public Base {
    public:
        using Base::fun;
        using Base::fun2;

        // overriden method fun, no conflict, choose this method if type is Derived
        void fun() { std::cout << "derived" << std::endl; }
};

int main(int argc, char* argv[])
{
    Private p;
    Public u;
    Derived d;

    // generates a compiler error since Base is privately inherited
    //p.fun();
    p.fun2(); // OK, output: base2

    u.fun(); // OK, output: base
    u.fun2(); // OK, output: base2

    // use Derived::fun since override
    d.fun(); // OK, output: derived
    d.Base::fun(); // OK, output: base
    d.fun2(); // OK, output: base2

    return 0;
}

Hope that can help

Upvotes: 0

Brian Bi
Brian Bi

Reputation: 119239

The standard has a special rule for this case.

When a using-declaration brings names from a base class into a derived class scope, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (if any) in a base class (rather than conflicting).

([namespace.udecl]/15)

Note that as usual, you can force Base::fun to be called by doing d.Base::fun().

Upvotes: 3

Related Questions