4

派生クラスによってオーバーライド (またはオーバーライド可能) する必要があるメソッドを C# でどのように宣言しますか (おそらくアセンブリの外部でも)、実際のクラス内からのみ呼び出し可能にする必要がありますか?

(つまり、C++ のプライベート仮想関数のように)

[編集]まさに私が意図したものです:「これは私の動作を変更する方法ですが、この関数を直接呼び出すことはまだ許可されていません (それを呼び出すには、私の基本クラスだけが行う難解な呼び出しが必要になるため)」
private virtual

明確にするために、C# での最適な表現は何ですか?

4

8 に答える 8

3

「実際のクラス内」でのみ呼び出し可能にする必要があると言うとき、基本クラスまたは派生クラスを意味しますか? これらはいずれも単独では実行できません。最も近いのは、保護されたメソッドを使用することです。つまり、宣言クラス、派生クラス、およびさらに派生したクラスから呼び出すことができます。

于 2009-01-05T22:44:46.800 に答える
2

C#は、C++よりも「プライベート」をより強力に保証します。C ++では、実際にプライベート仮想メソッドをオーバーライドできます。ただし、これは、基本クラスのコードが派生クラスのコードを実行できることを意味します。プライベートメソッドは本当にプライベートであり、同じクラスのメソッドによってのみ呼び出すことができるという約束を破ります。

ここで役に立たないのは、C++では仮想キーワードを繰り返す必要がないということです。このようなミステリーをリバースエンジニアリングするのは困難です。

#include "stdafx.h"
#include <iostream>

class Base {
private:
    virtual void Method() = 0;
public:
    void Test() {
        Method();
    }
};
class Derived : public Base {
private:
    void Method() { std::cout << "Who the heck called me?"; }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Base* p = new Derived;
    p->Test();
}

私は私的継承の可能な役割があることに同意します。C#言語の設計者は「いいえ」と言いました。けれど。

于 2009-01-05T23:13:27.710 に答える
2

これは、vboctorがすでに言及していることの例です。

public class Base
{
    private Func<Base, int> func;
    protected void SetFunc(Func<Base, int> func)
    {
        this.func = func;
    }

    private void CallFunc()
    {
        if (func != null)
        {
            var i = func(this);
        }
    }
}

public class Sub : Base
{
    private void DoFuncyStuff()
    {
         this.SetFunc(b => 42);
    }
}
于 2009-03-27T01:06:06.750 に答える
2

プライベート メンバーは、子クラスには表示されません。保護された仮想は、あなたが望むように機能すると思いますか?

アップデート:

ここでは、C# 内で関数の継承とオーバーライドを使用して何ができるかについて詳しく説明します。やや意味のある例を使用しようとしましたが、それはクラス設計が貧弱であり、この方法で説明されているクラスの実装はお勧めしません。ただし、これにより、元の問題を許容できる方法で解決するための手段が得られることを願っています。具象クラスがそのメンバーのいずれかを呼び出すのを防ぐ方法はありませんが、構造がとにかくこのようなものである場合、おそらく問題にはなりません。

public abstract class Animal
{
    public void DisplayAttributes()
    {
        Console.WriteLine(Header());
        Console.WriteLine("Name: " + Name());
        Console.WriteLine("Legs: " + Legs());
        Console.WriteLine();
    }

    protected virtual int Legs()
    {
        return 4;
    }

    private string Header()
    {
        return "Displaying Animal Attributes";
    }

    protected abstract string Name();
}

public class Bird : Animal
{
    protected override string Name()
    {
        return "Bird";
    }

    protected override int Legs()
    {
        return 2;
    }
}

public class Zebra : Animal
{
    protected override string Name()
    {
        return "Zebra";
    }
}

public class Fish : Animal
{
    protected override string Name()
    {
        return "Fish";
    }

    protected override int Legs()
    {
        return 0;
    }

    private string Header()
    {
        return "Displaying Fish Attributes";
    }

    protected virtual int Gils()
    {
        return 2;
    }

    public new void DisplayAttributes()
    {
        Console.WriteLine(Header());
        Console.WriteLine("Name: " + Name());
        Console.WriteLine("Gils: " + Gils());
        Console.WriteLine();
    }
}

class Program
{
    static void Main(string[] args)
    {
        Bird bird = new Bird();
        bird.DisplayAttributes();
        //Displaying Animal Attributes
        //Name: Bird
        //Legs: 2

        Zebra zebra = new Zebra();
        zebra.DisplayAttributes();
        //Displaying Animal Attributes
        //Name: Zebra
        //Legs: 4


        Fish fish = new Fish();
        fish.DisplayAttributes();
        //Displaying Fish Attributes
        //Name: Fish
        //Gils: 2

        List<Animal> animalCollection = new List<Animal>();
        animalCollection.Add(bird);
        animalCollection.Add(zebra);
        animalCollection.Add(fish);

        foreach (Animal animal in animalCollection)
        {
            animal.DisplayAttributes();
            //Displaying Animal Attributes
            //Name: Bird
            //Legs: 2

            //Displaying Animal Attributes
            //Name: Zebra
            //Legs: 4

            //Displaying Animal Attributes
            //Name: Fish
            //Legs: 0
            //*Note the difference here
            //Inheritted member cannot override the
            //base class functionality of a non-virtual member
        }
    }
}

この例では、Bird、Zebra、および Fish はすべて Name および Legs メソッドを呼び出すことができますが、この例のコンテキスト内では、そうすることが必ずしも有用であるとは限りません。さらに、Fish で示されているように、具象派生クラスのインスタンスに対して DisplayAttributes() を変更できます。ただし、foreach ループのように Animal を見ている場合は、実際の動物の種類に関係なく、基本クラスの DisplayAttributes の動作が得られます。これが、複製したい機能のタイプを提供するのに役立つことを願っています.

于 2009-01-05T22:41:39.443 に答える
1

そのためにデリゲートを使用することを検討しましたか? 派生クラスが保護されたプロパティを介してデリゲートを設定するか、コンストラクターに渡すことができます。基本クラスのプライベート メソッドである内部実装にデリゲートをデフォルト設定することもできます。

于 2009-01-06T00:57:48.700 に答える
0

これは意図したとおりに機能しないと思いますが、疑似コードをスケッチさせてください。

public interface BaseClassFunction {
    void PleaseCallMe();
}

public class BaseClass {
    private BaseClassFunction fn;
    public BaseClass(BaseClassFunction fn) {
        this.fn = fn;
    }
    private CallMe() {
        fn.PleaseCallMe();
    }
    public PublicCallMe() {
        CallMe();
    }
}

private class DerivedClassFunction : BaseClassFunction {
    void PleaseCallMe() { ... do something important ... }
}

public class DerivedClassFunction {
    public DerivedClassFunction() : BaseClass(new DerivedClassFunction()) {
    }
}
于 2009-01-05T23:07:30.157 に答える
0

なぜプライベートにする必要があるのですか?ここでは、Protected で十分です。サブクラスの作成者に、呼び出しできないコードを書くように依頼しています。これは何を達成しますか?とにかく、彼らはそのコードを使用できます。

于 2009-01-05T22:42:13.250 に答える