14

抽象メソッドでは new/override が必要であるのに、仮想メソッドでは必要でないのはなぜですか?

サンプル 1:

abstract class ShapesClass
{
    abstract public int Area(); // abstract!
}

class Square : ShapesClass
{
    int x, y;

    public int Area() // Error: missing 'override' or 'new'
    {
        return x * y;
    }
}

コンパイラは次のエラーを表示します: 現在のメンバーでその実装をオーバーライドするには、override キーワードを追加します。それ以外の場合は、新しいキーワードを追加します

サンプル 2:

class ShapesClass
{
    virtual public int Area() { return 0; } // it is virtual now!
}

class Square : ShapesClass
{
    int x, y;

    public int Area() // no explicit 'override' or 'new' required
    {
        return x * y;
    }
}

デフォルトでメソッドを非表示にすることで、これは正常にコンパイルされます。

技術的な違いを完全に理解しています。しかし、なぜ言語がそのように設計されたのか疑問に思います。「サンプル2」も同様の制限を設けたほうがよいのではないでしょうか?つまり、ほとんどの場合、親クラスと同じ名前のメソッドを作成すると、通常はそれをオーバーライドしようとします。したがって、Override/New を明示的に指定することは、仮想メソッドでも意味があると思います。

この動作に設計上の理由はありますか?

更新: 2 番目のサンプルでは実際に警告が発生します。最初のサンプルは、抽象メソッドを実装するためにサブクラスが必要であるため、エラーを示しています。VSで警告が表示されませんでした..今では完全に理にかなっています。ありがとう。

4

5 に答える 5

11

.NET 3.5 SP1に同梱されているC#3.0コンパイラ、または.NET 4.0に同梱されているC#4.0コンパイラのいずれかを使用すると、最初の例で次のエラーが発生します。

エラーCS0534:'ConsoleApplication3.Square'は継承された抽象メンバー'ConsoleApplication3.ShapesClass.Area()'を実装していません

そして、2番目のものに対する次の警告

警告CS0114:'ConsoleApplication3.Square.Area()'は継承されたメンバー'ConsoleApplication3.ShapesClass.Area()'を非表示にします。現在のメンバーがその実装をオーバーライドするようにするには、overrideキーワードを追加します。それ以外の場合は、新しいキーワードを追加します。

最初のケースでは、基本メソッドを実際にオーバーライドしていないため、エラーになります。つまり、具象クラスに抽象メソッドの実装がありません。2番目のケースでは、コードが技術的に正しいため警告ですが、コンパイラーはそれが意図したものではないと疑っています。これは、「警告をエラーとして扱う」コンパイル設定を有効にすることが一般的に良い考えである理由の1つです。

だから私はあなたの振る舞いを再現することはできません、そしてコンパイラの振る舞いは私には正しく見えます。使用しているコンパイラのバージョンはどれですか?

于 2010-09-03T09:47:54.413 に答える
7

これがC#仕様からの直接の答えです。

...継承されたスコープからアクセス可能な名前を非表示にすると、警告が報告されます。例では

class Base
{
    public void F() {}
}
class Derived: Base
{
    public void F() {}      // Warning, hiding an inherited name
}

Derived で F を宣言すると、警告が報告されます。継承された名前を非表示にすることは、基本クラスの個別の進化を妨げるため、特にエラーではありません。たとえば、Base の新しいバージョンで、以前のバージョンのクラスには存在しなかった F メソッドが導入されたために、上記の状況が発生した可能性があります。上記の状況がエラーであった場合、個別にバージョン管理されたクラス ライブラリの基本クラスに変更を加えると、派生クラスが無効になる可能性があります。継承された名前を非表示にすることによって発生する警告は、 new 修飾子を使用して排除できます。

class Base
{
    public void F() {}
}
class Derived: Base
{
    new public void F() {}
}

new 修飾子は、Derived の F が「新規」であること、および継承されたメンバーを非表示にすることを実際に意図していることを示します。

于 2010-09-03T09:56:07.063 に答える
3

違いは、抽象メソッドはオーバーライドする必要がありますが、仮想メソッドはオーバーライドしないことです。

すべての抽象メンバーを実装せずに (非抽象クラスで) 抽象クラスを継承するのはエラーですが、overrideまたはnew仮想メソッドを指定せずにクラスから継承する場合にのみ警告が表示されます。

于 2010-09-03T09:45:15.553 に答える
0

抽象メソッドが隠されて実装されていないため、最初の方法でコンパイラエラーが発生すると思います(したがって、事実上、クラスが間違っており、理由を理解するのは難しいでしょう)。2番目のケースでは、クラスが使用可能であるため、警告のみが表示されます。

于 2010-09-03T09:46:54.880 に答える