2016-09-06 8 views
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; 
} 

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

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

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

ответ

22

ли это:

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

Это не работает (такая же ошибка C2247). Я использую MSVC 2013, если это актуально. – Carlton

+1

Вы уверены? Он должен работать? Вы пишете ведущий '::'? – Bathsheba

+0

Положительный. Я скопировал/вставил ваш код и очистил/перестроил мой проект. – Carlton

5

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

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

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

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

4

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

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

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

8

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

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

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

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

7

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

9.2 (N4594)

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

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

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

+0

Очень хороший анализ того, почему это происходит. Благодарю. – Carlton

+0

@Carlton Добро пожаловать – PcAF

+0

Блестящий! Я как бы интуитивно понял, что что-то вроде этого должно продолжаться, но это делает очень ясным * точно * то, что происходит (и объясняет, почему установка '::' на передний план устраняет проблему). –

Смежные вопросы