2012-01-11 64 views
5

有人能解释一下这两个例子有什么不同吗?多态/覆盖

A类

protected virtual string GetData()

B类

private override string GetData()

和以下:

A类

protected string GetData()

B类

private string GetData()

假设 'B类' 从 'A类' 继承。

我总是假设你需要在子类中使用virtual,如果你想重写某个方法,需要在子类中使用override,但是我尝试删除关键字并且程序编译正常。究竟有什么区别,如果有的话?

+0

您是否看到B.GetData()下的波浪状?你在视图+错误列表中看到警告吗?很难错过,当你知道你在做什么时,使用* new *关键字。 – 2012-01-11 23:56:29

+1

在第一个例子中,B的方法不能是私有的。它不会编译。 – TrueWill 2012-01-11 23:58:14

回答

4

您显示的第二个示例隐藏了父级的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() 

实际上这个样品是无效的,因为它应该在派生类使用new关键字public new void Test2()

它的作用就像操作符重载一样。它实际上并没有覆盖任何东西。当你有确切的类型Derived它调用新的方法。

你必须非常小心隐藏成员,它完全不像重写(类)或实现(接口)。只有当你有确切的类型它会调用new方法,否则它仍然会调用基类型的方法!

+0

谢谢,这有助于清除它! – 2012-01-11 23:48:12

+0

不客气:) – Aidiakapi 2012-01-11 23:50:29

3

区别在于,在第一种情况下,你是重写,而在第二种情况下,你隐藏的是完全不同的。

在第一种情况:

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 
    } 
} 

在第二种情况下,你只是隐藏的实现的GetData(但你永远即使变量引用了B类型的实例,也能够通过变量类型A调用A的实现。请注意,这与覆盖行为的方式完全不同。

+0

谢谢你的解释! – 2012-01-11 23:48:30

0
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类型,但是在执行该方法时,代码被解析为“真实”实现。 (请参阅谷歌虚拟功能表和解决原则)

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

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

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