Подтвердить что ты не робот

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

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

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.
Как разрешить двусмысленность и рассказать компилятору, я просто делаю вызов статического метода?

4b9b3361

Ответ 1

Сделайте это:

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

Ответ 2

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

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

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

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

Ответ 3

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

9.2 (N4594)

[...] Имя класса также вставляется в область самого класса; это известно как имя введенного класса. Для проверки доступа имя с именем incested-class рассматривается как имя публичного участника. [...]

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

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

Ответ 4

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

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

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

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

Ответ 5

Несколько возможностей:

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

  • Принесите функцию private в пространство имен Derived1, написав using Base::SomeStaticMethod;