Ответ 1
Сделайте это:
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
::Base::SomeStaticMethod();
// ^^
// Notice leading :: for accessing root namespace.
}
};
Из-за расположения сторонней библиотеки у меня есть что-то вроде следующего кода:
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
.
Как разрешить двусмысленность и рассказать компилятору, я просто делаю вызов статического метода?
Сделайте это:
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)
[...] Имя класса также вставляется в область самого класса; это известно как имя введенного класса. Для проверки доступа имя с именем incested-class рассматривается как имя публичного участника. [...]
Обратите внимание, что даже если вы наберете 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
.
Несколько возможностей:
Не используйте структуру наследования для вызова метода. Используйте ::Base::SomeStaticMethod()
для вызова. Base
доступен в глобальном пространстве имен.
Принесите функцию private
в пространство имен Derived1
, написав using Base::SomeStaticMethod;