繁体   English   中英

C#中虚拟方法的问题

[英]issue of virtual method in C#

在MSDN中,提到了

http://msdn.microsoft.com/zh-CN/library/9fkccyh4(VS.80).aspx

我感到困惑的是,“通过包含使用override修饰符的属性声明,可以在派生类中覆盖虚拟继承的属性”是什么意思?

(这是虚拟和抽象之间的第二个区别)

预先感谢乔治

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

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

在您从AbstractClass派生的类中(上面的AbstractClass仅用于说明目的;由于它没有实现的方法/属性,因此您可以创建接口而不是抽象类),您将必须提供以下实现MyProperty 否则,它将无法编译。 您可以通过“覆盖” MyProperty来执行此操作,您不想引入新成员,而只是为先前定义的属性提供实现。

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

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

virtualabstract

  • 如果将一个类方法(或属性)标记为virtual ,那么如果您选择从该类继承 (又称为derive ),则可以使用override关键字将其override

    virtual关键字旨在引起这种想法,即该方法可能是实际调用的方法,也可能不是。 因此,我始终将virtual成员视为默认实现 ,这意味着它表示可以泛化的功能,例如Human类上的Eat()方法,可能涉及用手吃饭。 但是, ChineseHuman类可能会覆盖Eat()默认实现 ,以便允许使用筷子的实现。 最后,由于虚拟方法和属性是默认实现 ,因此定义该成员的类必须提供方法或属性的完整实现。 所有Human对象必须知道如何 Eat()

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

  • 如果将类方法(或属性)标记为abstract ,则如果您选择从该类继承 ,则必须使用override关键字将其override

    abstract关键字旨在引起这样的想法:该类仅支持成员表示的功能,并且没有可以针对该功能归纳的任何通用逻辑。 换句话说, abstract成员只是概念上的 ,因此缺少实现。 在实现继承关系时,C#要求我们override抽象成员有点令人困惑,但是在这种情况下,这实际上意味着我们正在通过具体的实现重写空概念。 Human类的abstract成员的一个示例可能是Speak() 对于所有Human对象来说,不会有一种通用的说话方式,也不是本能的,因为它需要语言来表达。 注意:有人可能会说Speak()属于interface

    面向对象的思维方式可以声明abstract成员表示要学习的行为(方法)和要获取的知识或信念(属性)。 Speak()Human类对象的学习行为。 一个ChineseHuman可以学会Speak()不同于一个EnglishHuman也不知道怎么Speak()仅仅是因为他们都是Human

细微差别:

  • virtual方法不需要被覆盖。
  • 没有virtual类这样的东西。
  • abstract成员只能出现在abstract类上。 在上述例子中,具有abstract的方法Human类意味着Human是一个abstract类,而且,因此,一个Human不能使用短语实例化var baby = new Human(); 相反, BabyHuman类应该继承自Human ,并且应实例化为var baby = new BabyHuman(); 因为BabyHuman()HumanEnglishHumanChineseHuman都还继承HumanEnglishHuman可以继承BabyHuman ,而不是Human 成为Humanabstract因为我们不仅仅是单纯的Human
  • abstract成员不能被隐藏,只有它们的override实现可以(在继承链的更进一步)。 例如, BabyHuman必须实现abstract Speak()方法作为override 如果EnglishHuman继承自BabyHuman ,则可以使用new关键字使用自己的实现隐藏Speak()BabyHuman实现(请参见下面的“ C#中的方法隐藏”)。
  • abstract类可以具有virtual成员。 这是interfaceabstract类之间的主要区别。 从这个意义上讲, abstract类既可以定义合同,也可以定义该类行为的模板,而interface只能定义合同。

代码参考:

您能解释一下令人困惑的地方吗? 可以像其他任何方法一样覆盖属性。

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

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

如果在基类中声明虚拟方法,则可以在派生类中重写该方法。

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

}

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

注意MyDerivedClass中的override修饰符。

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

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

virtual关键字的意思是,在从Bar派生的类中,您可以重写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;
      }
   }
}

说明:使用Baz类型的对象时,将调用其SomeProperty版本,除非将该类型强制转换为Bar。 如果您将Baz的SomeProperty定义为虚拟的,则从Baz派生的类也可以覆盖它(实际上,这可能是必需的-无法立即记住)。

进一步说明:抽象方法没有实现; 当您将一个类添加到您的类时,您还必须将该类标记为抽象类,并且无法实例化该类的新实例,如下所示:

MyAbstractType m = new MyAbstractType();

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM