【问题标题】:How to call a static method from a private base class?如何从私有基类调用静态方法?
【发布时间】:2017-01-13 23:16:38
【问题描述】:

由于第三方库的布局,我有如下代码:

struct Base
{
    static void SomeStaticMethod(){}
};

struct Derived1: private Base {};

struct Derived2: public Derived1 {
    void SomeInstanceMethod(){
        Base::SomeStaticMethod();
    }
};

int main() {
    Derived2 d2;
    d2.SomeInstanceMethod();

    return 0;
}

我在使用 MSVC 时遇到编译器错误 C2247:

Base::SomeStaticMethod 不可访问,因为 Derived1 使用 private 从 Base 继承。

我知道由于 private 说明符,我无法通过继承从 Derived2 访问 Base 成员,但我仍然应该能够调用 Base 的静态方法 - 无论 @987654325 之间的任何继承关系如何@ 和 Derived2.
如何解决歧义并告诉编译器我只是在调用静态方法?

【问题讨论】:

    标签: c++ static-methods private-inheritance


    【解决方案1】:

    这样做:

    struct Derived2: public Derived1 {
        void SomeInstanceMethod(){
            ::Base::SomeStaticMethod();
    //      ^^
    //      Notice leading :: for accessing root namespace.
        }
    };
    

    【讨论】:

    • 这不起作用(同样的错误 C2247)。如果相关,我正在使用 MSVC 2013。
    • 你确定吗?它应该工作吗?你写了领先的::吗?
    • 阳性。我复制/粘贴了您的代码并清理/重建了我的项目。
    • 当使用 gcc(4.8 和 6)和 clang(3.7.0) 编译时,它确实修复了您的示例。
    • 比尔盖茨创造了 MSVC 错误,吉尔贝茨发现了它:-) 这让我很开心
    【解决方案2】:

    我认为 michalsrb 的答案更好,但为了完整性:

    namespace
    {
        void SomeStaticMethodProxy()
        {
            return Base::SomeStaticMethod();
        }
    }
    
    struct Derived2: public Derived1 {
        void SomeInstanceMethod(){
            SomeStaticMethodProxy();
        }
    };
    

    也可以。

    【讨论】:

      【解决方案3】:

      其他答案提供了解决问题的方法,我将尝试解释发生了什么。这是因为 injected-class-name

      9.2 (N4594)

      [...]类名也被插入到类本身的作用域中;这被称为注入类名。 出于访问检查的目的,注入的类名被视为公共成员名。[...]

      请注意,即使您输入Base::SomeStaticMethod(),显然SomeStaticMethod 会在Base 范围内查找(它是限定名称),但名称Base 本身也必须以某种方式查找,(在本例中作为非限定名称(因为它不会出现在范围解析运算符之后))

      当您在Derived2 中搜索(未验证的)名称Base 时,首先搜索Derived2 范围,然后搜索Derived1 范围,然后搜索Base 范围,最后 injected-class-name 被发现。然后进行访问控制(因为访问控制发生在名称查找之后),它会发现您查找的名称是Base 的成员,不能从Derived2 访问。

      【讨论】:

      • 太棒了!我有点直觉,肯定会发生这样的事情,但这使得确切地非常清楚发生了什么(并解释了为什么将::放在前面可以解决问题)。
      【解决方案4】:

      如果你想通过层次结构调用它,你可以这样做:

      struct Derived1: private Base {
      protected:
          using Base::SomeStaticMethod;
      };
      
      struct Derived2: public Derived1 {
          void SomeInstanceMethod(){
              Derived1::SomeStaticMethod();
          }
      };
      

      否则,如果您想直接在Base 上调用它,请按照@michalsrb 提到的方式进行操作。

      【讨论】:

        【解决方案5】:

        几种可能性:

        1. 不要使用继承结构来调用方法。使用::Base::SomeStaticMethod() 调用它。 Base 可在全局命名空间中访问。

        2. 通过编写using Base::SomeStaticMethod;,将private 函数带入Derived1 的命名空间

        【讨论】:

          猜你喜欢
          • 2016-01-05
          • 2012-05-24
          • 1970-01-01
          • 2019-03-27
          • 2010-10-10
          • 2013-07-12
          • 2017-10-08
          • 2015-06-26
          • 2015-04-08
          相关资源
          最近更新 更多