Как вызвать статический метод из частного базового класса?

Из-за компоновки сторонней библиотеки у меня есть что-то вроде следующего кода:

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

Я получаю ошибку компилятора C2247 с MSVC:

Base:: SomeStaticMethod недоступен, поскольку Derived1 использует private для наследования от Base.

Я знаю, что не могу получить доступ Base члены из Derived2 через наследование из-за частного спецификатора, но я все еще должен иметь возможность вызывать статический метод Base - независимо от каких-либо наследственных отношений между Base а также Derived2,
Как устранить неоднозначность и сообщить компилятору, что я просто вызываю статический метод?

5 ответов

Решение

Сделай это:

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

Я думаю, что ответ michalsrb лучше, но для полноты:

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

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

тоже будет работать.

Другие ответы дают способ решить проблему, я постараюсь объяснить, что происходит. Это из-за введенного имени класса.

9,2 (N4594)

[...] Имя класса также вставляется в область действия самого класса; это известно как имя введенного класса. В целях проверки доступа имя введенного класса обрабатывается так, как если бы оно было публичным именем члена.[...]

Обратите внимание, что даже если вы введете Base::SomeStaticMethod()очевидно SomeStaticMethod ищется в Base область (это квалифицированное имя), но имя BaseСамо по себе также нужно искать как-то(в этом примере как неквалифицированное имя (потому что оно не появляется после оператора разрешения области видимости))

Что происходит, когда вы ищете (неквалифицированное) имя Base в Derived2, первый Derived2 область поиска, затем Derived1 область поиска и затем Base область поиска ищется и, наконец, вводится-имя-класса. Затем происходит контроль доступа (потому что контроль доступа происходит после поиска имени), и он обнаружит, что имя, которое вы искали, Baseчлен, который не доступен из Derived2,

Вы можете сделать это, если хотите вызвать его через иерархию:

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

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

В противном случае, сделайте, как упомянуто @michalsrb, если вы хотите вызвать его напрямую Base,

Пара возможностей:

  1. Не используйте структуру наследования для вызова метода. использование ::Base::SomeStaticMethod() называть это. Base доступен в глобальном пространстве имен.

  2. Принеси private функция в пространство имен Derived1 написав using Base::SomeStaticMethod;

Другие вопросы по тегам