我对following code生成的错误感到困惑。 在Derived :: doStuff中,我可以通过调用它直接访问Base :: output。
为什么我无法在可以调用output()
的相同上下文中创建指向output()
的指针?
(我认为protected / private管理你是否可以在特定的上下文中使用名称,但显然这是不完整的?)
我的解决方法是callback(this, &Derived::output);
而不是callback(this, Base::output)
正确的解决方案吗?
#include <iostream>
using std::cout; using std::endl;
template <typename T, typename U>
void callback(T obj, U func)
{
((obj)->*(func))();
}
class Base
{
protected:
void output() { cout << "Base::output" << endl; }
};
class Derived : public Base
{
public:
void doStuff()
{
// call it directly:
output();
Base::output();
// create a pointer to it:
// void (Base::*basePointer)() = &Base::output;
// error: 'void Base::output()' is protected within this context
void (Derived::*derivedPointer)() = &Derived::output;
// call a function passing the pointer:
// callback(this, &Base::output);
// error: 'void Base::output()' is protected within this context
callback(this, &Derived::output);
}
};
int main()
{
Derived d;
d.doStuff();
}
编辑:我很想知道这在标准中的位置,但大多数情况下我只是试图围绕这个概念。我认为我的问题是callback
无权访问Derived
的受保护成员,但如果您传递指针,则可以调用Derived::output
。 Derived
来自Derived
的受保护成员与来自Derived
的{{1}}受保护成员有何不同?
答案 0 :(得分:2)
简而言之,这是“因为标准是这么说的。”为什么?我不知道,我已经通过电子邮件发送了几个标准人员,但尚未收到回复。
具体来说,11.5.1(来自C++0x FCD):
超出额外的访问权限检查 那些在前面第11章中描述的那些 在非静态数据时应用 成员或非静态成员函数 是其命名的受保护成员 class(11.2)114如前所述, 访问受保护的成员是 因为引用发生而被授予 在朋友或某些C班的成员。 如果访问是形成指针 成员(5.3.1),. nested-name-specifier应表示C. 或者来自C的类。所有其他 访问涉及(可能是隐含的) 对象表达式(5.2.5)。在这 case,对象的类 表达式应为C或类 源自C。
修改
此外,您将看到您将代码更改为以下内容,根据标准指定的内容,它将干净地编译(并运行):
void (Base::*derivedPointer)() = &Derived::output;
答案 1 :(得分:1)
编辑:我不确定这是否是“标准中的这个位置?”问题还是“为什么这样设计?”问题,这回答了后者(我没有标准本身的副本)
我认为这是因为具有受保护或朋友访问base
的函数可以通过将函数指针传递给不应该访问base
私有成员的方法来绕过访问保护。
在此示例中,callback
无法访问base
,因此无法调用其中一个私有函数。