问题

2009-03-03 26 views

回答

1

你能解释一下而已混乱?属性可以像任何其他方法一样被覆盖。

public class Base { 
    public virtual int Prop1 { get { ... } set { ... } } 
} 

public class Derived : Base { 
    public override int Prop1 { get { ... } set { ... } } 
+0

我的困惑不是重写属性,而是为什么它是抽象和虚拟之间的差异 - “”通过包含使用override修饰符的属性声明,可以在派生类中重写虚拟继承属性。“?请参阅我引用的MSDN上下文。 – George2 2009-03-03 13:13:45

+2

抽象成员没有实现,所以_必须被覆盖。虚拟成员有一个实现,并且可以覆盖_may_。这是不同的。 – 2009-03-03 13:18:42

+0

明白了,MSDN的话太模糊了。 :-) – George2 2009-03-03 13:21:03

1

如果你在你的基类中声明了一个虚方法,你可以在你的派生类中覆盖它。

class MyBaseClass 
{ 
    public virtual void MyOverridableMethod() 
    { 
      ... 
    } 

} 

class MyDerivedClass : MyBaseClass 
{ 
    public override void MyOverridableMethod() 
    { 
     ... 
    } 
} 

通知在MyDerivedClass override修饰符。

10

虚拟和抽象之间的唯一区别在于,抽象方法或抽象类在已定义的类(抽象类)中没有实现,并且它必须在子类中被覆盖;而虚拟方法或属性在已定义的类中有一个实现,所以在子类中重写它并不是强制性的。

public abstract AbstractClass 
{ 
    // This class cannot be instantiated, since it is 
    // abstract, and the class is abstract because 
    // it has an abstract member 

    public abstract MyProperty {get; set; } 
} 

在您从抽象类派生类(上面的抽象类是只为说明目的,因为它没有任何方法/性的判定有一个实现,你可以创建一个接口,而不是一个抽象类),你将不得不提供MyProperty的实施。否则,它不会编译。 通过'覆盖'MyProperty来做到这一点,你不想引入一个新成员,而只是提供一个以前定义的属性的实现。

public class ConcreteClass : AbstractClass 
{ 
    public override MyProperty { 
     get 
     { 
      return _someValue; 
     } 
     set 
     { 
      if(_someValue != value) _someValue = value; 
     } 
} 
1

好吧,假设您有一个基类,并且该基类本身是从另一个类派生的。

public class Bar : Foo 
{ 
    virtual public int SomeProperty { get; set; } 
} 

什么virtual关键字意味着,在从酒吧派生的类,则可以覆盖SomeProperty改变其行为:

public class Baz : Bar 
{ 
    private int thisInt; 
    override public int SomeProperty 
    { 
     get { return thisInt; } 
     set 
     { 
     if(value < 0) 
     { 
      throw new ArgumentException("Value must be greater than or equal to zero."); 
     } 
     thisInt = 0; 
     } 
    } 
} 

澄清:当使用类型巴兹的对象,它的版本SomeProperty被调用,除非类型被转换为Bar。如果你将Baz的SomeProperty定义为虚拟的,那么从Baz派生出来的类也可以覆盖它(事实上,这可能是必需的 - 不能从脑海中回想起来)。

进一步说明:抽象方法没有实现;当你添加一个到您的类,还必须将类标记为抽象的,你不能实例化它的新的实例,就像这样:

MyAbstractType m = new MyAbstractType(); 

虚拟成员,而另一方面,可以有一个实现(如SomeProperty,上面),所以你不必标记类的抽象,你可以实例化它们。

6

我可以理解混乱。我曾去过那里,所以我将分享我如何保持基本差异直...

virtualabstract

  • 如果一个类的方法(或属性)是 标virtual,那么可能是 使用override 关键字覆盖,如果你选择继承 (又名获得)从该类。

    virtual关键字旨在唤起这样的想法:该方法可能是也可能不是实际调用的方法。因此,我始终认为virtual成员为默认实现,这意味着它代表了可以推广的功能,例如类中的Eat()方法,这可能涉及用手进食。但是,ChineseHuman类可能会替代默认实现Eat(),以便允许替代使用斩波棒的实现。最后,由于虚拟方法和属性是默认实现,定义该成员的类必须提供方法或属性的完整实现。所有Human对象必须知道如何Eat()

    面向对象的思维方式可能会声明virtual成员代表本能Eat()Human类对象的本能。 A ChineseHuman可能学习Eat()用筷子。

  • 如果一个类的方法(或属性)是 标记abstract,那么它必须是 使用override 关键字,如果你选择从该类继承 覆盖。

    abstract关键字旨在唤起类只有支持该成员表示的功能,并且没有任何可以通用于该功能的通用逻辑。换句话说,abstract成员只有概念,因此他们缺乏一个实现。当我们实现一个继承关系时,C#向我们询问override抽象成员有点令人困惑,但在这种情况下,这实际上意味着我们用一个具体实现覆盖了空的概念。Human类的abstract成员的示例可能是Speak()。所有的对象都不会有一种常见的说话方式,也不是本能的,因为它需要语言来表达。注意:有些人可能会认为Speak()属于interface

    面向对象的思维方式可能会声明abstract成员表示要学习的行为(方法)以及要获得的知识或信念(属性)。到Speak()学过行为的一个Human类对象。 A ChineseHuman可能会学习到Speak()EnglishHuman不同,并且都不知道如何Speak(),因为它们都是Human

细微差别:

  • virtual方法并不需要重写。
  • 有没有这样的事情,作为一个virtual类。
  • abstract成员只能出现在abstract类。在上面的例子中,在Human类别上使用abstract方法意味着Humanabstract类别,并且因此不能使用短语var baby = new Human();实例化Human。相反,BabyHuman类应继承自Human,它应该实例化为var baby = new BabyHuman();。因为BabyHuman()HumanEnglishHumanChineseHuman二者也都从Human继承,EnglishHuman可以从BabyHuman而不是Human继承。正在Humanabstract,因为我们都不仅仅是Human
  • abstract成员不能被隐藏,只有他们的override实现可能是(进一步继承链)。例如,BabyHuman必须将abstractSpeak()方法实施为override。如果EnglishHuman继承自BabyHuman,则它可以使用new关键字(请参阅下面的“C#中的方法隐藏”参考)隐藏BabyHumanBabyHuman实现Speak()及其自己的实现。
  • abstract类可以有virtual成员。这是interfaceabstract类之间的主要区别。从这个意义上讲,一个abstract类可以定义类的行为的合同和模板,而interface只定义合同。

代码参考:在C#