2

次のクラス階層があるとします。

class Base
{
  protected:

    virtual void foo() = 0;

    friend class Other;
};

class Derived : public Base
{
  protected:

    void foo() { /* Some implementation */ };
};

class Other
{
  public:

    void bar()
    {
      Derived* a = new Derived();

      a->foo(); // Compiler error: foo() is protected within this context
    };
};

私もそれを変更できると思いますa->Base::foo()foo()、クラスでは純粋に仮想であるBaseため、呼び出しはDerived::foo()とにかく呼び出しになります。

ただし、コンパイラはを拒否しているようa->foo()です。論理的だと思いますが、その理由がよくわかりません。私は何かが足りないのですか?この特殊なケースを処理することはできません(すべきではありません)?

ありがとうございました。

4

5 に答える 5

6

Base::foo()動的ディスパッチ(ランタイムバインディング)のように、メソッド名をクラス名で修飾する場合は適用されません。仮想かどうかに関係なく、常にBaseの実装を呼び出します。この場合、それは純粋な仮想であるため、実装はなく、コンパイラーは文句を言います。foo()foo()

2番目の問題は、C++では友情が継承されないことです。Otherに特別なアクセスをしたい場合は、特にDerivedの友達である必要がありますDerived

一方、これは機能します。

Base* a = new Derived();

a->foo(); 

ここでは、パブリックでfoo()あるBase*whereを呼び出しており、クラス名で修飾されていないため、動的ディスパッチを使用して、のバージョンを呼び出すことになります。foo()foo()DerivedFoo

于 2010-05-04T17:38:08.130 に答える
1

私はあなたがこれを行うことができると思います

void bar()
{
  Base* a = new Derived();

  a->foo(); 
};
于 2010-05-04T17:40:45.100 に答える
0

この「友達クラスその他」を入れてみてください。派生クラスで。

更新:考えてみてください。私は、aをBaseポインターに変更する必要があるというTylerに同意します。

Base* a = new Derived();
于 2010-05-04T17:36:50.647 に答える
0

しかし、コンパイラはそれを拒否しているようです。

何を拒否しますか?コンパイラが、OtherがBaseポインタを介してfoo()関数を呼び出すことを許可していないと言っているようです。確かにそうではないはずです。

あなたの基本的な質問に答えるために、友情は継承されません....期間。パーミッションスコープは名前解決と同じ段階でチェックされ、foo()は使用している名前内で保護されているため、呼び出すことはできません。

一方、ポリモーフィズムはポインタのリダイレクトによって解決され、名前解決やアクセス許可とは何の関係もありません。

于 2010-05-04T17:38:52.963 に答える
0

残念ながら、私の意見では、C++では本質的に親しみやすさが損なわれています。

  • 継承されません
  • すべての内部への無制限のアクセスを許可し、制限する可能性はありません

私はそれを「現状のまま」使用することをあきらめ、今ではほとんどの場合Keyパターンを使用しています(より良い名前がないため)。

///
/// Key definition
///
class Friend;

class FriendKey: boost::noncopyable { friend class Friend; FriendKey() {} };

///
/// Base/Derived definition
///
class Base
{
public:

  void mySpecialMethod(const FriendKey&) { this->mySpecialMethodImpl(); }

private:
  virtual void mySpecialMethodImpl() = 0;
}; // class Base

class Derived: public Base
{
public:

private:
  virtual void mySpecialMethodImpl() {}
}; // class Derived

///
/// Friend definition
///
class Friend
{
public:
  void mySpecialCall()
  {
    Derived d;
    d.mySpecialMethod(FriendKey());
  }
}; // class Friend

概念は単純です。各クラスはキーを宣言し(フォワードヘッダーでも可能)、それらへの特別なアクセスを許可したいクラスは、このキーに対してのみ可能になります。

もちろん、(キーの推移性によって)悪用される可能性があるため、完全ではありません。しかし、C ++ではすべてを悪用できるため、マキャヴェリよりもマーフィーから保護することの方が問題です。

于 2010-05-05T07:31:11.973 に答える