25

サードパーティ ライブラリのレイアウトにより、次のようなコードがあります。

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 がプライベートを使用して Base から継承しているためです。

Baseプライベート指定子のため、継承を介してメンバーにアクセスできないことはわかっていますが、との間の継承関係に関係なく、 -Derived2の静的メソッドを呼び出すことができるはずです。 あいまいさを解決し、静的メソッドを呼び出しているだけであることをコンパイラに伝えるにはどうすればよいですか?BaseBaseDerived2

4

5 に答える 5

22

これを行う:

struct Derived2: public Derived1 {
    void SomeInstanceMethod(){
        ::Base::SomeStaticMethod();
//      ^^
//      Notice leading :: for accessing root namespace.
    }
};
于 2016-09-06T13:18:50.030 に答える
8

他の回答は問題を解決する方法を提供します。何が起こっているのかを説明しようと思います。これは、injected-class-nameが原因です。

9.2 (N4594)

[...]クラス名もクラス自体のスコープに挿入されます。これは、注入されたクラス名として知られています。アクセス チェックの目的で、injected-class-nameはパブリック メンバー名であるかのように扱われます。[...]

と入力してもBase::SomeStaticMethod()、明らかにスコープ内SomeStaticMethodで検索されます (修飾名です) が、名前自体も何らかの方法で検索する必要があることに注意してください (この例では、非修飾名として(スコープ解決演算子の後に表示されないため)) BaseBase

で(修飾されていない)名前を検索するBaseDerived2、最初にDerived2スコープが検索され、次にDerived1スコープが検索され、次にBaseスコープが検索され、最後に注入されたクラス名が見つかります。その後、アクセス制御が行われ (アクセス制御は名前検索の後にBase行われるため)、検索した名前がからアクセスできない のメンバーであることがわかりますDerived2

于 2016-09-06T17:44:31.137 に答える
8

michalsrbの答えの方が良いと思いますが、完全を期すために:

namespace
{
    void SomeStaticMethodProxy()
    {
        return Base::SomeStaticMethod();
    }
}

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

も機能します。

于 2016-09-06T13:22:37.860 に答える
6

階層を介して呼び出す場合は、これを行うことができます。

struct Derived1: private Base {
protected:
    using Base::SomeStaticMethod;
};

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

それ以外の場合は、 @michalsrb で直接呼び出したい場合は、言及したとおりに実行してくださいBase

于 2016-09-06T13:20:01.450 に答える