0

オブジェクトの2つの「系統」があります。

  1. Carの基本クラスですSportsCar
  2. Engineの基本クラスですSportsEngine

Carのフィールドの1つはengine、タイプのEngineです。SportsCarこれをオーバーライドし、代わりengineにタイプがのフィールドを持ちますSportsEngine

のコンストラクターCarは次のとおりです。

public Car() {
    engine = new Engine();
}

のコンストラクターSportsCarは次のとおりです。

public SportsCar() : base() {
    engine = new SportsEngine();
}

アイデアは、私が車のタイプの階層を持っており、各車が適切な種類のエンジン(車の機能の特定の側面を決定する)を持っているということです。車の階層のあるポイントをサブクラス化すると、この車のエンジンが既存の車と同じ馬力、重量、燃料使用量などであるかどうかを判断し、既存のエンジンを使用してengineフィールドにデータを入力できます。追加する新しい車に固有のエンジンを搭載する必要があると判断した場合は、Engine階層をサブクラス化して新しいエンジンを作成し、フィールドをオーバーライドしてengine、新しい車のコンストラクターを変更して正しく初期化できます。

問題は、C#を正しく理解している場合、新しいインスタンスを作成するとB、エンジンが2回初期化されることです。厳密に言えば、それは現在の非常に単純なケースを壊すことはありません。しかし、何が起こるかというと、私がnew SportsCar()それを最初に呼び出すengine = new Engine();と、engine = new SportsEngine();

概念的には、スポーツカーを作るときは、一般的なエンジンを入れずに、すぐに引き出してから、スポーツエンジンを入れます。これは、コードが実行することになると思います。

実際には、最初の結果がとにかく破棄されるときに、なぜ2つのコンストラクター呼び出しを行う必要があるのでしょうか。

私の解決策はvirtual void CreateEngine() { engine = new Engine(); }、ベースの建設業者に電話をかけ、子供用の車には決して電話をかけないことでした。次に、各車は独自のを実装しoverride void CreateEngine()ます。それで:

  1. このアプローチで見られない問題はありますか?
  2. どうやらコンストラクターで仮想メソッドを呼び出すのは悪いことです。私の場合は例外ですか?
4

3 に答える 3

1

Vlad が指摘したように、コンストラクターで仮想関数を呼び出すこと自体は悪くありません。別のオプションは、コンストラクターを介してエンジンを注入することです。これを調べる 1 つの方法は、車自体がエンジンを作成するのか、それとも誰かがそこに置くのかということです。次に、次のようになります。

public class Car {
    public Engine Engine { get; private set; }
    public Car(Engine engine) {
        Engine = engine;
    }
}
public class SportsCar: Car {
    public new SportsEngine Engine { 
        get { return (SportsEngine)base.Engine; } 
    }
    public SportsCar(SportsEngine engine): base(engine) {}
}

次にCarFactory、クリスの回答で指摘されているように、車を構築することもできます。

于 2012-10-13T12:45:01.563 に答える
1

C# では、コンストラクターで仮想メソッドを呼び出すこと自体は悪くありません。初期化されていないフィールドにアクセスしていない場合は、すべて問題ありません。C++ のアプローチとは対照的に、コンストラクターで仮想メソッドを呼び出すと、基本メソッドではなく、実際のオブジェクトのメソッドが呼び出されます。(詳細については、これらの 記事を参照してください。)

仮想関数を使用したアプローチに問題はありません。スポーツカー専用の engine へのアクセサ as sportsengine が必要かもしれません。

SportsCar に SportsEngine フィールドを宣言させるという古いアプローチについて、もう 1 つ注意してください。新しいフィールドは古いフィールドを置き換えません。フィールドをオーバーライドすることはできません。つまり、最終的に 2 つのエンジンを搭載した車になることになりますが、これは奇妙なことです。SportsEngineが である限りEngine、既存のフィールドを再利用する必要があります。

于 2012-10-13T12:42:30.470 に答える
0

サブクラスが構築されるとき、スーパークラス (サブクラスの派生元のクラス) が具象クラス (抽象クラスではない) である場合、サブクラス コンストラクターは、スーパークラスのフィールドとメソッドを次のように作成するために、スーパークラスのコンストラクターを呼び出します。サブクラス作成の一部。

あなたの場合、engine = new SportsEngine();クラスエンジンはSportEngineの派生クラスを構築する一環として具象クラスであるため、エンジンのコンストラクターも呼び出されます。

私が提案するのは、エンジンを抽象クラス ( C# 抽象クラスのチュートリアル) にしてから、エンジンの抽象クラス GenericEngine と SportsEngine から派生させることです。エンジンの変数型を使用して、これらの派生クラスのいずれかを保持できます。

デリゲート デザイン パターンに関するこの記事から始めることもできます。

于 2012-10-13T12:48:12.847 に答える