13

だから私はこの投稿からC++の動作と一致するかどうかを確認するためにC#で遊んでいました: http ://herbsutter.com/2013/05/22/gotw-5-solution-overriding-virtual-functions/行動:

public class BaseClass
{
    public virtual void Foo(int i)
    {
        Console.WriteLine("Called Foo(int): " + i);
    }

    public void Foo(string i)
    {
        Console.WriteLine("Called Foo(string): " + i);
    }
}

public class DerivedClass : BaseClass
{
    public void Foo(double i)
    {
        Console.WriteLine("Called Foo(double): " + i);
    }
}

public class OverriddenDerivedClass : BaseClass
{
    public override void Foo(int i)
    {
        base.Foo(i);
    }

    public void Foo(double i)
    {
        Console.WriteLine("Called Foo(double): " + i);
    }
}

class Program
{
    static void Main(string[] args)
    {
        DerivedClass derived = new DerivedClass();
        OverriddenDerivedClass overridedDerived = new OverriddenDerivedClass();

        int i = 1;
        double d = 2.0;
        string s = "hi";

        derived.Foo(i);
        derived.Foo(d);
        derived.Foo(s);

        overridedDerived.Foo(i);
        overridedDerived.Foo(d);
        overridedDerived.Foo(s);
    }
}

出力

Called Foo(double): 1
Called Foo(double): 2
Called Foo(string): hi
Called Foo(double): 1
Called Foo(double): 2
Called Foo(string): hi

したがって、基本クラスからのより具体的な Foo(int) よりも、暗黙的に変換された int を double に優先するようです。または、基本クラスから Foo(int) を非表示にしますか? しかし、その後: Foo(string) が非表示にならないのはなぜですか? 非常に矛盾しているように感じます... Foo(int) をオーバーライドするかどうかも問題ではありません。結果は同じです。ここで何が起こっているのか誰か説明できますか?

(はい、派生クラス (Liskov など) で基本メソッドをオーバーロードするのは悪い習慣であることはわかっていますが、それでも OverriddenDerivedClass の Foo(int) が呼び出されないとは思いませんか?!)

4

1 に答える 1

8

この例でどのように機能するかを説明するにはOverriddenDerivedClass:

ここでメンバー検索の C# 仕様を見てください: http://msdn.microsoft.com/en-us/library/aa691331%28VS.71%29.aspx

それはルックアップがどのように行われるかを定義します。

特に、次の部分を見てください。

最初に、T で宣言された N という名前のすべてのアクセス可能な (セクション 3.5) メンバーのセットと、T の基本型 (セクション 7.3.1) が構築されます。オーバーライド修飾子を含む宣言はセットから除外されます。

あなたの場合、NですFoo()Declarations that include an override modifier are excluded from the setそのため はoverride Foo(int i)セットから除外されます。

したがって、オーバーライドされていないものだけがFoo(double i)残り、それが呼び出されます。

この例ではこのように動作しますOverriddenDerivedClassが、これは例の説明ではありませんDerivedClass

それを説明するには、仕様の次の部分を見てください。

次に、他のメンバーによって非表示になっているメンバーがセットから削除されます。

Foo(double i)inは基本クラスからDerivedClass隠されているため、セットから削除されます。Foo(int i)

ここで難しいのは、次の部分です。

S の基本型で宣言された M と同じシグネチャを持つすべてのメソッドがセットから削除されます。

「でも待ってください! はと同じ署名を持ってFoo(double i) いないFoo(int i)ので、セットから削除すべきではありません!」と言うかもしれません。

ただし、int から double への暗黙的な変換があるため同じシグネチャを持つと見なされ、セットから削除されます。Foo(int i)

于 2013-05-23T08:46:46.033 に答える