1

在 MSDN 中提到,

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

我很困惑这个项目是什么意思“可以通过包含使用覆盖修饰符的属性声明来覆盖派生类中的虚拟继承属性。”?

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

提前谢谢,乔治

4

5 回答 5

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

在从 AbstractClass 派生的类中(上面的 AbstractClass 仅用于解释目的;由于它没有具有实现的方法/属性,因此您可以创建接口而不是抽象类),您必须提供MyProperty. 否则,它不会编译。您通过“覆盖” MyProperty 来做到这一点,您不想引入新成员,而只是为之前定义的属性提供实现。

public class ConcreteClass : AbstractClass
{
    public override MyProperty {
       get
       {
            return _someValue;
       }
       set
       {
            if( _someValue != value ) _someValue = value;
       }
}
于 2009-03-03T13:13:14.363 回答
6

我能理解这种困惑。我以前去过那里,所以我将分享我如何保持基本差异...

virtualabstract

  • 如果一个类方法(或属性)被标记virtual,那么 如果您选择从该类继承 (也称为派生),则可以 使用关键字覆盖它。该关键字旨在唤起这样一种想法,即该方法可能是也可能不是实际调用的方法。因此,我一直认为成员是默认实现,这意味着它代表可以泛化的功能,例如类上的方法,这可能涉及用手吃饭。但是,一个类可能会覆盖的默认实现override

    virtualvirtualEat()HumanChineseHumanEat(),以便允许使用筷子代替的实现。最后,因为虚拟方法和属性是默认实现,所以定义该成员的类必须提供方法或属性的完整实现。所有Human对象都必须知道如何 Eat()

    面向对象的思维方式可能会宣称virtual成员代表本能。ToEat()是类对象的本能。HumanAChineseHuman可以学会Eat()筷子。

  • 如果一个类方法(或属性)被标记abstract,那么 如果您选择 从该类继承,则必须使用关键字覆盖它。该关键字旨在唤起这样一种想法,即该类仅支持该成员表示的能力,并且没有任何通用逻辑可以针对该功能进行概括。换句话说,成员只是概念性的,因此它们缺乏实现。当我们实现继承关系时,C# 要求我们抽象成员有点令人困惑,但在这种情况下,这实际上意味着我们用具体实现覆盖了空概念。一个例子override

    abstractabstractoverrideabstract一个Human类的成员可能是Speak(). 对于所有Human对象来说,不会有一种共同的说话方式,也不是本能的,因为它需要语言来表达。注意:有些人可能会争辩说,它Speak()属于 aninterface而不是。

    面向对象的思维方式可能会声明abstract成员代表要学习的行为(方法)和要获得的知识或信念(属性)。ToSpeak()是类对象的学习行为。HumanA 的ChineseHuman学习方式可能Speak()与 an 不同EnglishHuman,但两者都不知道如何学习,Speak()因为他们都是Human.

细微差别:

  • virtual方法不需要被覆盖。
  • 没有类这样的东西virtual
  • abstract成员只能出现在abstract类中。在上面的例子中,abstract在类上有一个方法Human意味着它Human是一个abstract类,因此,aHuman不能使用短语 来实例化var baby = new Human();。相反,BabyHuman该类应该继承自Human,并且应该实例化为var baby = new BabyHuman();。因为 aBabyHuman()是 aHuman并且EnglishHuman两者ChineseHuman都继承自HumanEnglishHuman所以可以继承自BabyHuman而不是Human。存在Humanabstract因为我们都不仅仅是简单的东西Human
  • abstract成员不能被隐藏,只有它们的override实现可能是(在继承链上更进一步)。例如,BabyHuman必须将该abstract Speak()方法实现为override. 如果EnglishHuman继承自BabyHuman,则它可以使用关键字隐藏 的BabyHuman实现及其自己的实现(请参阅下面的“C# 中的方法隐藏”参考)。Speak()new
  • abstract类可以有virtual成员。interface这是一个和一个abstract类之间的主要区别。从这个意义上说,一个abstract类可以定义一个契约和类行为的模板,而一个interface只定义一个契约。

代码参考:

于 2009-04-16T17:07:55.710 回答
1

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

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

public class Derived : Base {
  public override int Prop1 { get { ... } set { ... } }
于 2009-03-03T13:12:29.280 回答
1

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

例子

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

}

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

注意 MyDerivedClass 中的 override 修饰符。

于 2009-03-03T13:13:08.000 回答
1

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

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),因此您不必标记类抽象,并且可以实例化它们。

于 2009-03-03T13:14:57.213 回答