2013-07-08 38 views
1
class Parent 
{ 
    public void foo() 
    { 
     Console.WriteLine("Hello from the foo inside Parent"); 
    } 

    public virtual void bar() 
    { 
     Console.WriteLine("Hello from the bar inside Parent."); 
    } 

    public void foobar() 
    { 
     Console.WriteLine("Hello from the foobar inside Parent."); 
    } 
} 
class Child : Parent 
{ 
    public void foo() 
    { 
     base.foo(); 
     Console.WriteLine("Hello from the foo inside Child"); 
    }   

    public override void bar() 
    { 
     base.bar(); 
     Console.WriteLine("Hello from the bar inside Child."); 
    } 

    public new void foobar() 
    { 
     base.foobar(); 
     Console.WriteLine("Hello from the foobar inside Child.");    
    } 
} 

上面就是我使用来测试我在C#中继承knowlege的代码,但我这里有一个困惑:孩子里面C#继承和压倒一切的

  1. 功能foo()隐藏的foo()家长。
  2. 功能bar()里面的孩子隐藏父母的bar()
  3. 功能foobar()孩子隐藏在里面的父母的bar()()

所有三个功能使用不同的技术来隐藏父功能。任何人都可以请引导我,这三个之间有什么不同,以及哪一个使用什么时候?

回答

2

首先,1和3是一样的,编译器/ IDE(Visual Studio中)会自动将您的意思做3号,如果你1号。你会发现,它把一个绿线的名义下foo()并告诉您使用new关键字。因此,在现实中,只有两种类型的基于继承的方法改变的:

  1. 方法覆盖
  2. 方法隐藏

方法覆盖是当一个类声明其方法是虚拟的,基本上说'任何继承我的类都可以自由地覆盖这个'。这意味着无论如何,如果子类覆盖该方法,则会调用被覆盖的版本。

另一方面,隐藏方法是孩子反叛,并说'只要我作为一个孩子班级存在,我将忽略我的父母实施,而不是这样做'。这里的诀窍是,当孩子类被视为父类时,父类的实现被调用。

下面是一个例子,假设正在使用类设置:

Child c = new Child(); 
c.foo(); 
c.bar(); 
Parent p = c; 
p.foo(); 
p.bar(); 

注意,Child c可以存储在父变量,因为它继承。 从父类继承的任何子类都可以被视为其父类的一个实例。

现在尝试加入这个类混进去:

class MaleChild : Parent 
{ 
    public new void foo() 
    { 
     base.foo(); 
     Console.WriteLine("Hello from the foo inside MaleChild"); 
    } 

    public override void bar() 
    { 
     base.bar(); 
     Console.WriteLine("Hello from the bar inside MaleChild."); 
    } 
} 

和运行类似的测试:

Parent[] p = new Parent[2]; 

p[0] = new Child(); 
p[1] = new MaleChild(); 

p[0].foo(); 
p[0].bar(); 
p[1].foo(); 
p[1].bar(); 

现在你看,即使两个继承的类都被视为他们的父母,重写的方法对于继承的类是唯一的。这允许父类为它的工作方式定义一个基本的大纲,而子类对此进行细化并更具体地做事。然而,因为子类可以完成父母的所有事情,所以可以将其视为父母。

这个概念被称为多态。

1

首先,在第一和第三个是相同的,唯一的区别是第三个不会给编译时警告

Child.foo()”隐藏继承的成员`Parent.foo( )”。如果隐藏的目的

继承的真正价值显示出来,当你有基本类型的变量,不知道该变量指向实例的类型使用新的 关键字。

请检查前三个调用的输出以及它们与最近三次调用的不同。

Parent p = new Child(); 
Child c = new Child(); 

p.foo(); 
p.bar(); 
p.foobar(); 
Console.WriteLine("------------------------"); 
c.foo(); 
c.bar(); 
c.foobar(); 
2

要看到差别尝试下面的代码:

Console.WriteLine("Parent->Parent"); 
Parent p = new Parent(); 
p.foo(); 
p.bar(); 
p.foobar(); 

在这种情况下,你有Parent型指向Parent类的实例变量。这里没有任何东西被隐藏或覆盖。父类的方法被调用。现在创建Child类型,它指向的Child实例变量:

Console.WriteLine("Child->Child"); 
Child c = new Child(); 
c.foo(); 
c.bar(); 
c.foobar(); 

在这种情况下,子类的所有方法被调用。也没什么有趣的。现在创建Parent类型,它指向的Child实例变量:

Console.WriteLine("Parent->Child"); 
Parent p = new Child(); 
p.foo(); // you have warning and parent method is invoked 
p.bar(); // child overridden method invoked 
p.foobar(); // no warning, parent method is invoked 

在这种情况下,你可以看到多态性行动 - 方法,这些方法在子类中重写被调用。如果方法未被覆盖,则调用父方法。但是,你也有一个警告消息:

警告1 'Namespace.Child.foo()' 隐藏继承成员 'Namespace.Parent.foo()'。如果需要隐藏,请使用新关键字。

它说的是,你在子类中的方法用相同的签名方法父类,其中隐藏父类的实现已宣布。从最后一个样本可以看出,隐藏与重写不同。当你有父类型的变量时,那么在子中重写的成员将被调用。但隐藏的方法在最后一种情况下不会被调用。

通常你不需要这样的行为(即隐藏一些成员),这就是为什么编译器会警告你。但如果由于某种原因您需要此行为(例如您没有自己的父级代码,并且无法使父级方法虚拟为),那么您应该使用new关键字来抑制此警告并显示您明白自己在做什么。这就是为什么你没有看到foobar方法的警告。

+0

请你解释一下,在你的第二个代码示例中,为什么/如何重写被调用的方法,而我们甚至没有实例化孩子?由于我对多态不熟悉,所以请不要介意我的问题对你来说是否愚蠢! –

+1

@KamranAhmed我改变了样品的顺序,最后显示最有趣的情况。所以,我想你是在问最后一个案子。实际上你在这儿实例化了一个小孩 - 'new Child()'是实例化的。但是您将对此实例的引用分配给基本类型的变量。 –