如何从私有库 class 调用静态方法?
How to call a static method from a private base class?
由于第三方库的布局,我有类似下面的代码:
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 not accessible because Derived1 uses private to inherit from Base.
我知道由于私有说明符,我无法通过继承从 Derived2
访问 Base
成员,但我仍然应该能够调用 Base
的静态方法 -不管 Base
和 Derived2
.
之间有任何继承关系
如何解决歧义并告诉编译器我只是在调用静态方法?
这样做:
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
::Base::SomeStaticMethod();
// ^^
// Notice leading :: for accessing root namespace.
}
};
如果想通过层级调用可以这样做:
struct Derived1: private Base {
protected:
using Base::SomeStaticMethod;
};
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
Derived1::SomeStaticMethod();
}
};
否则,如果您想直接在 Base
上调用它,请按照@michalsrb 提到的方法进行操作。
几种可能性:
不要使用继承结构来调用方法。使用 ::Base::SomeStaticMethod()
调用它。 Base
可在全局命名空间中访问。
通过写using Base::SomeStaticMethod;
将private
函数带入Derived1
的命名空间
我认为 michalsrb 的回答更好,但为了完整起见:
namespace
{
void SomeStaticMethodProxy()
{
return Base::SomeStaticMethod();
}
}
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
SomeStaticMethodProxy();
}
};
也可以。
其他答案提供了解决问题的方法,我将尝试解释发生了什么。是因为injected-class-name.
9.2 (N4594)
[...]The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.
For purposes of access checking, the injected-class-name is treated as if it were a public member name.[...]
请注意,即使您键入 Base::SomeStaticMethod()
,显然 SomeStaticMethod
会在 Base
范围内查找(它是限定名称),但名称 Base
本身也必须以某种方式查找,(在这个例子中作为一个 非限定名称 (因为它没有出现在范围解析运算符之后))
发生的情况是,当您在 Derived2
中搜索(未限定的)名称 Base
时,首先搜索 Derived2
范围,然后搜索 Derived1
范围,然后搜索 Base
范围,最后找到 injected-class-name。然后进行访问控制(因为访问控制发生在 在 名称查找之后)并且它会发现您查找的名称是 Base
的成员,无法从Derived2
.
由于第三方库的布局,我有类似下面的代码:
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 not accessible because Derived1 uses private to inherit from Base.
我知道由于私有说明符,我无法通过继承从 Derived2
访问 Base
成员,但我仍然应该能够调用 Base
的静态方法 -不管 Base
和 Derived2
.
之间有任何继承关系
如何解决歧义并告诉编译器我只是在调用静态方法?
这样做:
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
::Base::SomeStaticMethod();
// ^^
// Notice leading :: for accessing root namespace.
}
};
如果想通过层级调用可以这样做:
struct Derived1: private Base {
protected:
using Base::SomeStaticMethod;
};
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
Derived1::SomeStaticMethod();
}
};
否则,如果您想直接在 Base
上调用它,请按照@michalsrb 提到的方法进行操作。
几种可能性:
不要使用继承结构来调用方法。使用
::Base::SomeStaticMethod()
调用它。Base
可在全局命名空间中访问。通过写
using Base::SomeStaticMethod;
将
private
函数带入Derived1
的命名空间
我认为 michalsrb 的回答更好,但为了完整起见:
namespace
{
void SomeStaticMethodProxy()
{
return Base::SomeStaticMethod();
}
}
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
SomeStaticMethodProxy();
}
};
也可以。
其他答案提供了解决问题的方法,我将尝试解释发生了什么。是因为injected-class-name.
9.2 (N4594)
[...]The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name. For purposes of access checking, the injected-class-name is treated as if it were a public member name.[...]
请注意,即使您键入 Base::SomeStaticMethod()
,显然 SomeStaticMethod
会在 Base
范围内查找(它是限定名称),但名称 Base
本身也必须以某种方式查找,(在这个例子中作为一个 非限定名称 (因为它没有出现在范围解析运算符之后))
发生的情况是,当您在 Derived2
中搜索(未限定的)名称 Base
时,首先搜索 Derived2
范围,然后搜索 Derived1
范围,然后搜索 Base
范围,最后找到 injected-class-name。然后进行访问控制(因为访问控制发生在 在 名称查找之后)并且它会发现您查找的名称是 Base
的成员,无法从Derived2
.