22

virtualしたがって、修飾子と一緒に修飾子を使用することはできないようoverrideです。

virtual- オーバーライド可能なメソッド

override- 親のクラスで同じ名前のメソッドをオーバーライドしているメソッド

これにより、子クラスのメソッドをオーバーライドすると、その子に子がある場合、そのメソッドを再度オーバーライドすることはできないと思います。

そして、メソッド宣言に and を入れるoverrideと、C# でコンパイル エラーが発生すると言っても過言ではありません。virtual

ただし、以下で作成したコードがなぜそのように機能するのか理解できません

using System;
public class DrawingObject
{
public virtual void Draw()
{
    Console.WriteLine("Drawing Object");
}
}
public class DrawDemo
{
     public static int Main()
     {
          DrawingObject[] dObj = new DrawingObject[3];


          dObj[0] = new DrawingObject();
           dObj[1] = new Line();
           dObj[2] = new LittleLine();

           foreach (DrawingObject drawObj in dObj)
           {
                drawObj.Draw();
           }
            Console.Read();
           return 0;
       }
  }
 public class Line : DrawingObject
 {
       public override void Draw()
       {// the method above me is in fact virtual because LittleLine overid it?
               Console.WriteLine("I'm a Line.");
       }
  }
  public class LittleLine : Line
  {
       public override void Draw()
       {
              Console.WriteLine("I'm a Little Line.");
         }
    }

出力は次のとおりです。

描画オブジェクト

私はラインです。

私はリトルラインです。

したがって、 の draw メソッドは、Lineによってオーバーライドされたように見えますLittleLine。このコードは実際にはオーバーライドしていませんか、それともコンパイラが他のトリックを行っていますか? virtualまたは、 andのコンテキストを理解していませんoverrideか?

4

6 に答える 6

31

特定のメソッドをvirtual1 回だけ宣言できますが、override何度でも宣言できます。オーバーライドは最終的なものではなく、最初のオーバーライド クラスから継承するクラスを制限しません。最終的に実行されるメソッドは、仮想メソッドをオーバーライドする最後のメソッドです。したがって、コードは期待どおりに動作します。

C# はオーバーライドに関して非常に冗長です。C++ や Java よりも多くの指定子があります。プログラマーが正確な意図を指定できるようにするためです。

  • virtualメソッドをサブクラスでオーバーライドできるように指定するために使用します。
  • override仮想であることがわかっているメソッドをオーバーライドしていることを指定するために使用します (そうでない場合、コンパイラはエラーを報告します)。
  • sealedそれ以上のオーバーライドを防ぐために使用します。
  • そしてnew、オーバーライドする代わりに非表示にするために使用します。

これは混乱を招き、時には煩わしいこともありますが、実際に何をしているのかを確実に把握し、意図を自己文書化することができます。

于 2012-06-28T17:50:04.620 に答える
4

したがって、仮想修飾子をオーバーライド修飾子と一緒に使用することはできません。

それはそう。であると宣言されているメソッドでオーバーライドしない限り、メソッドは仮想のままですsealed。(何かをオーバーライドしている場合にのみ、メソッドで変更を使用できます。) C# 4 仕様のセクション 10.6.5 から:sealed

インスタンス メソッドの宣言に、sealed 修飾子が含まれている場合、そのメソッドは、sealed メソッドと呼ばれます。インスタンス メソッドの宣言に seal 修飾子が含まれている場合は、override 修飾子も含める必要があります。seal 修飾子を使用すると、派生クラスがメソッドをさらにオーバーライドできなくなります。

于 2012-06-28T17:52:53.880 に答える
2

この振る舞いは正しいです。継承されたクラスで仮想メソッドをオーバーライドしたくない場合は、次のように「封印」のマークを付けることができます。

public class Line : DrawingObject
 {
       public sealed override void Draw()
       {
               Console.WriteLine("I'm a Line.");
       }
  }

その後、LittleLine クラスは Draw メソッドをオーバーライドできなくなります。

于 2012-06-28T17:54:13.000 に答える
2

あなたは単に仕組みを誤解していると思いますvirtual。ここで説明されているように、継承のレベルは 1 つに限定されません。たとえば、次のようになります。

クラスで宣言または継承されたすべての仮想メソッドには、そのクラスに関するメソッドの最も派生した実装が存在します。クラス R に関する仮想メソッド M の最も派生した実装は、次のように決定され ます
。それ以外の場合、R に関する
M
の最も派生した実装は、R の直接の基底クラスに関する M の最も派生した実装と同じです。

于 2012-06-28T17:53:19.687 に答える
1

意図したとおりに機能したようです。

dObj[0] = 新しい DrawingObject();
dObj[1] = new Line();
dObj[2] = new LittleLine();

Draw() を呼び出しており、ループ中

出力 Drawing Object I'm a Line は次のとおりです。私はリトルラインです

dObj[0].Draw() -> 「描画オブジェクト」 dObj[1].Draw() -> 「私は線です。」dObj[2].Draw() -> 「私は小さな線です」

そのため、Line の描画メソッドは、LittleLine によってオーバーライドされたかのように見えます

はい、それはあなたが期待したものではありませんか?メソッドは基本クラスで Virtual としてマークされており、それをオーバーライドしました。「追加」したい場合は、他のパターンを使用する必要があります。おそらくデコレータ。

于 2012-06-28T17:53:54.570 に答える
1

virtualメソッドが仮想メソッド テーブルを介してディスパッチされることを意味します。メソッドが仮想の場合、派生クラスでのそのメソッドへの参照は vtable を通過する必要があります。派生クラスがそれをオーバーライドするという理由だけで、それを非仮想化することはできません -LittleLineにキャストされた場合はどうなりDrawingObjectますか? DrawingObjectではない正しい実装を見つける必要があります

于 2012-06-28T17:52:32.430 に答える