错误:'void Base :: output()'在此上下文中受到保护

时间:2010-04-07 16:28:35

标签: c++ access-modifiers

我对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::outputDerived来自Derived的受保护成员与来自Derived的{​​{1}}受保护成员有何不同?

2 个答案:

答案 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,因此无法调用其中一个私有函数。