【问题标题】:effects of using declaration on name lookup for two exactly same names使用声明对两个完全相同名称的名称查找的影响
【发布时间】:2016-08-06 17:33:25
【问题描述】:

基本上,我的问题与名称查找和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?

因此,我的理解是现在我们应该有 both 名称可见,然后对于名称查找,应该有一些歧义。但实际上并非如此。是什么原因,或者换句话说,我误解了一些概念吗?

【问题讨论】:

标签: c++ name-lookup using-declaration


【解决方案1】:

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

using-declaration 将名称从基类带入派生类范围时,成员函数和 派生类中的成员函数模板覆盖和/或隐藏成员函数和成员函数 具有相同名称、参数类型列表 (8.3.5)、cv-qualification 和 ref-qualifier(如果有)的模板 基类(而不是冲突)。

([namespace.udecl]/15)

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

【讨论】:

    【解决方案2】:

    您引用的链接是针对 namespace 的,您应该引用 class using-declaration 的声明:

    如果派生类已经有一个具有相同名称、参数列表和限定条件的成员,则派生类成员会隐藏或覆盖(不与)从基类引入的成员。

    对于您发布的代码,Base 中的void fun()Derived 中的void fun() 隐藏,所以不,它们并非都是“可见的”,除非您在调用@987654328 时明确表示@,例如:

    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()protected 中的protected 或者你private/protected'ly 继承自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;
    }
    

    希望能帮到你

    【讨论】:

      猜你喜欢
      • 2015-02-23
      • 1970-01-01
      • 1970-01-01
      • 2015-11-11
      • 2016-12-25
      • 1970-01-01
      • 2019-04-24
      • 2023-03-24
      • 1970-01-01
      相关资源
      最近更新 更多