Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 多态/重写_C#_.net_Oop_Inheritance_Polymorphism - Fatal编程技术网

C# 多态/重写

C# 多态/重写,c#,.net,oop,inheritance,polymorphism,C#,.net,Oop,Inheritance,Polymorphism,有人能解释一下这两个例子的区别吗 甲级 受保护的虚拟字符串GetData() B类 private覆盖字符串GetData() 以及以下各项: 甲级 受保护的字符串GetData() B类 私有字符串GetData() 假设“B类”继承自“A类” 我一直认为,如果要重写某个方法,需要在超类中使用virtual,在子类中使用override,但是我尝试删除关键字,并且程序编译得很好。区别到底是什么,如果有的话?区别在于,在第一种情况下,您是覆盖的,而在第二种情况下,您是隐藏的,这是完全不同的 在第

有人能解释一下这两个例子的区别吗

甲级
受保护的虚拟字符串GetData()

B类
private覆盖字符串GetData()

以及以下各项:

甲级
受保护的字符串GetData()

B类
私有字符串GetData()

假设“B类”继承自“A类”


我一直认为,如果要重写某个方法,需要在超类中使用
virtual
,在子类中使用
override
,但是我尝试删除关键字,并且程序编译得很好。区别到底是什么,如果有的话?

区别在于,在第一种情况下,您是覆盖的,而在第二种情况下,您是隐藏的,这是完全不同的

在第一种情况下:

class B: A
{
    void Foo()
    {
        B b = new B();
        A a = b;

        a.GetData() //B's GetData() will be called
        b.GetData() //B's GetData() will be called
    }
}
另一方面,在第二种情况下:

class B: A
{
    void Foo()
    {
        B b = new B();
        A a = b;

        a.GetData() //A's GetData() will be called
        b.GetData() //B's GetData() will be called
    }
}

在第二种情况下,您只是隐藏了A的GetData()实现但您始终能够通过类型为A的变量调用A的实现,即使该变量引用类型为B的实例。请注意,这与重写的行为完全不同。

您显示的第二个示例隐藏了父级的GetData,而不是重写它

例如:

private class Base
{
    public virtual void Test()
    {
        Console.WriteLine("Base");
    }

    public void Test2()
    {
        Console.WriteLine("Base");
    }
}

private class Derived : Base
{
    public override void Test()
    {
        Console.WriteLine("Derived");
    }

    public void Test2()
    {
        Console.WriteLine("Derived");
    }
}

static void Main()
{
    Base b = new Base();
    Derived d = new Derived();
    Base dInB = new Derived();

    b.Test();
    d.Test();
    dInB.Test();

    b.Test2();
    d.Test2();
    dInB.Test2();

    Console.ReadKey(true);
}
它输出:

Base    // Base.Test()
Derived // Derived.Test()
Derived // Derived.Test()
Base    // Base.Test2()
Derived // Derived.Test2()
Base    // You think you're calling Derived.Test2(), but you actually call Base.Test2()
实际上,这个示例是无效的,因为它应该在派生类中使用
public new void Test2()
中的
new
关键字

它就像操作符重载一样工作。它实际上并没有覆盖任何内容。当您拥有确切的类型
派生的
时,它将调用新方法

隐藏成员时必须非常小心,这与重写(类)或实现(接口)完全不同。只有当您拥有精确类型时,它才会调用一个
新的
方法,否则它仍然会调用基类型的方法

public class A
{
    public virtual string GetData() { return "A";}
}

public class B : A
{
    public override string GetData() { return "B"; }
}
如果您使用下面代码块中的类,您期望得到什么

        A a = new A();
        B b = new B();
        A c = new B();

        Console.WriteLine(a.GetData());
        Console.WriteLine(b.GetData());
        Console.WriteLine(c.GetData());
这将打印“A”“B”“B”。变量c作为类型存储,但在执行该方法时,代码被解析为“实”实现。(虚拟功能表及解析原理见谷歌)

如果您不使用下面代码中的虚拟和覆盖,这将打印“A”“B”“A”


谢谢你的解释!你看到B.GetData()下面的曲线了吗?您是否在查看+错误列表中看到警告?很难忽略,当你知道自己在做什么时,使用new关键字。在第一个例子中,B的方法不能是私有的。它不会编译。
public class A
{
    public string GetData() { return "A";}
}

public class B : A
{
    public new string GetData() { return "B"; }
}