2

「コンポーネント」クラスに保護された仮想メソッドを追加して、「コンポジット」から呼び出すことができるようにするにはどうすればよいですか?

具体例として、以下のコードを見て、 のコンパイルエラーを回避する方法を教えてくださいDxCompositeShape.ComputeSize

abstract class DxShape // this is the Component
{
    public abstract void Paint();
    protected abstract void ComputeSize();
}

class DxCompositeShape : DxShape // this is the Composite
{
    public readonly IList<DxShape> Shapes = new List<DxShape>();

    public override void Paint()
    {
        this.ComputeSize();
    }

    protected override void ComputeSize()
    {
        foreach (DxShape sh in Shapes)
        {
            sh.ComputeSize(); // compiler error CS1540
        }
        // and some other logic here
    }
}

編集:サンプルを変更したので、ComputeSize代わりにInit(コンストラクターで Init を常に呼び出すことができると人々は想定しています)。

4

2 に答える 2

2

できません。別のオブジェクトの保護されたメンバーは、問題のオブジェクトが現在のオブジェクトと同じ型であることをコンパイラが確認できる場合にのみ呼び出すことができます。基本的に「保護」とは、「派生クラスは、このメンバーを自身のクラスで使用できる。

ここでの根本的な問題は、一部の特権クラス (「コンポジット」) が、基本クラスが独自の実装で派生クラスを使用するためだけに宣言する外部クラス (「コンポーネント」) のメソッドを呼び出せるようにすることです。

Initすべてのコンポジットが同じパッケージにある場合は、内部にすることをお勧めします。または、すべてのコンポジットが継承するコンポーネントのサブクラスを作成し、この特定のクラスInitにすべてのコンポーネントを呼び出す特権を与えることもできます。C++ では、フレンド宣言でそのようなことを行います。C# では、内部アクセスを慎重に使用することがおそらく正しい解決策です。

于 2013-08-07T13:00:22.533 に答える
1

Initialise()Init を呼び出す基本クラスで非仮想関数を作成します。

例えば:

abstract class DxShape
{
    protected void Initialise()
    {
        Init();
    }
    protected abstract void Init();
    //...
}

以下のコメントで指摘されているように、Initialiseパブリックまたは静的にする必要があります (C# のみ)。C++ では保護されたままにすることができます。C++ では、Init を非公開にし、への呼び出しを介してのみアクセスすることができますInitialise。非仮想インターフェイスを参照してくださいhttp://en.wikipedia.org/wiki/Non-virtual_interface_pattern

于 2013-08-07T12:55:34.240 に答える