3

我对以下代码生成的错误感到困惑。在 Derived::doStuff 中,我可以通过调用 Base::output 直接访问它。

为什么我不能output()在我可以调用的同一上下文中创建一个指针output()

(我认为受保护/私有管理是否可以在特定上下文中使用名称,但显然这是不完整的?)

我的写作方法是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,它就可以调用。that from 的 protectedDerived::output成员与that from 的 protected 成员有何不同?DerivedDerivedDerivedBase

4

2 回答 2

2

简而言之,“因为标准是这样说的”。为什么?我不知道,我已经给几个标准人员发了电子邮件,但还没有收到回复。

具体来说,11.5.1(来自C++0x FCD):

当非静态数据成员或非静态成员函数是其命名类 (11.2)114 的受保护成员时,将应用第 11 条中所述之外的附加访问检查,如前所述,授予对受保护成员的访问权限是因为引用出现在某个类 C 的朋友或成员中。如果访问要形成指向成员的指针 (5.3.1),则嵌套名称说明符应表示 C 或从 C 派生的类。所有其他访问都涉及(可能是隐式的)对象表达式(5.2.5)。在这种情况下,对象表达式的类应为 C 或从 C 派生的类。

编辑:

此外,您会看到您将代码更改为以下内容,根据标准指定的内容,它将干净地编译(和运行):

void (Base::*derivedPointer)() = &Derived::output;
于 2010-04-07T19:26:01.400 回答
1

编辑:我不确定这是否是“标准中的这个在哪里?” 问题或“为什么这样设计?” 问题,这回答了后者(我没有标准本身的副本可以玩)

我相信这是因为具有受保护或朋友访问权限base的函数可以通过将函数指针传递给不应访问base' 的私有成员的方法来绕过访问保护。

在此示例中,callback无权访问base,因此不应调用其私有函数之一。

于 2010-04-07T16:32:06.497 回答