我对 g++(5.1 版)下的访问声明有疑问。
class Base
{
public:
void doStuff() {}
};
class Derived : private Base
{
public:
// Using older access declaration (without using) shoots a warning
// and results in the same compilation error
using Base::doStuff;
};
template<class C, typename Func>
void exec(C *c, Func func)
{
(c->*func)();
}
int main()
{
Derived d;
// Until here, everything compiles fine
d.doStuff();
// For some reason, I can't access the function pointer
exec(&d,&Derived::doStuff);
}
g++ 编译上述代码失败:
test.cpp: In instantiation of ‘void exec(C*, Func) [with C = Derived; Func = void (Base::*)()]’: test.cpp:24:27: required from here
test.cpp:17:4: error: ‘Base’ is an inaccessible base of ‘Derived’ (c->*func)();
即使可以调用函数本身 (d.doStuff();
),即使我声明该函数可以从外部访问,指针也不能使用。
在某种程度上,私有(private)继承也很重要,因为 Derived
类选择仅从作为接口(interface)实现 IRL 的基类中公开一组特定成员。
注意:这是关于语言的问题,而不是类设计。
最佳答案
问题在于&Derived::doStuff
实际上并不是一个指向Derived
类成员的指针。来自 [expr.unary.op]:
The result of the unary
&
operator is a pointer to its operand. The operand shall be an lvalue or a qualified-id. If the operand is a qualified-id naming a non-static or variant memberm
of some classC
with typeT
, the result has type “pointer to member of classC
of typeT
” and is a prvalue designatingC::m
.
doStuff
不是 Derived
的成员。它是 Base
的成员。因此它具有指向 Base
或 void (Base::*)()
成员的类型指针。 using-declaration 在这里所做的只是帮助重载解析,来自 [namespace.udecl]:
For the purpose of overload resolution, the functions which are introduced by a using-declaration into a derived class will be treated as though they were members of the derived class.
这就是 d.doStuff()
起作用的原因。但是,通过函数指针,您试图在 Derived
对象上调用 Base
成员函数。这里没有重载解决方案,因为您直接使用函数指针,因此基类函数将无法访问。
您可能认为您可以将 &Derived::doStuff
转换为“正确”类型:
exec(&d, static_cast<void (Derived::*)()>(&Derived::doStuff));
但是根据 [conv.mem] 你也不能这样做,因为 Base
又是 Derived
的一个不可访问的基础:
A prvalue of type “pointer to member of
B
of type cvT
”, whereB
is a class type, can be converted to a prvalue of type “pointer to member ofD
of type cvT
”, whereD
is a derived class (Clause 10) ofB
. IfB
is an inaccessible (Clause 11), ambiguous (10.2), or virtual (10.1) base class ofD
, or a base class of a virtual base class ofD
, a program that necessitates this conversion is ill-formed.
关于c++ - 公共(public)访问声明不影响成员函数指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31518214/