在两个完全相同的名称的名称查找中使用声明的效果

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

本文关键字:查找 声明 两个      更新时间:2023-10-16

基本上,我的问题与名称查找和using声明有关(http://en.cppreference.com/w/cpp/language/namespace)
假设我们有以下(绝对愚蠢的)代码:

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?

因此,我的理解是,现在我们应该让两个名称都可见,然后对于名称查找,应该存在一些歧义。但事实并非如此。原因是什么?或者换句话说,我是否误解了一些概念?

对于这种情况,标准有一个特殊的规则。

using声明将基类中的名称带入派生类作用域时,成员函数和派生类中的成员函数模板覆盖和/或隐藏成员函数和成员函数具有相同名称、参数类型列表(8.3.5)、cv资格和ref限定符(如果有)的模板基类(而不是冲突的)。

([namespace.udcl]/15)

请注意,与往常一样,您可以通过执行d.Base::fun()来强制调用Base::fun

您引用的链接是针对namespace的,您应该使用声明来引用class,其中声明:

如果派生类已经有一个具有相同名称、参数列表和资格的成员,则派生类成员将隐藏或重写(与基类引入的成员不冲突)。

在您发布的代码的情况下,Base中的void fun()Derived中的void fun()隐藏,所以不,它们都不"可见",除非您在调用fun时是明确的,例如:

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

此外,由于您已经公开派生自Base,严格地说,您不需要using声明;在void fun()Base中的protected的情况下,或者private/protected是从Base继承的,例如:

#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;
}

希望这能帮助