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呼び出すことができます。の保護されたメンバーはDerived::output、の保護されたメンバーとどのようにDerived異なりDerivedますか?DerivedBase

4

2 に答える 2

2

要するに「規格にそう書いてあるから」です。なんで?よくわかりませんが、標準化担当者にメールを送りましたが、まだ返事がありません。

具体的には、11.5.1 ( C++0x FCDから):

非静的データメンバーまたは非静的メンバー関数がその命名クラス (11.2) の保護されたメンバーである場合、条項 11 で前述したものを超える追加のアクセスチェックが適用されます。アクセスがメンバーへのポインターを形成する場合 (5.3.1)、nested-name-specifier は C または C から派生したクラスを示す必要があります。他のすべてのアクセスには、 (おそらく暗黙の) オブジェクト式 (5.2.5)。この場合、オブジェクト式のクラスは C または C から派生したクラスでなければなりません。

編集:

また、標準の指定に従って、コードを次のように変更すると、問題なくコンパイル (および実行) されることがわかります。

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

編集:これが「標準のどこにあるのか」かどうかはわかりません。質問または「なぜそれがそのように設計されているのですか?」質問、これは後者に答えます(私は遊ぶための標準自体のコピーを持っていません)

これは、に保護されたアクセスまたはフレンドアクセスを持つ関数が、のプライベートメンバーbaseにアクセスできないメソッドに関数ポインタを渡すことにより、アクセス保護を回避できるためだと思います。base

この例では、callbackにアクセスできbaseないため、そのプライベート関数の1つを呼び出すことはできません。

于 2010-04-07T16:32:06.497 に答える