выпуск виртуального метода в C # - PullRequest
1 голос
/ 03 марта 2009

В MSDN упоминается

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

Я не совсем понимаю, что означает этот элемент: «Виртуальное наследуемое свойство может быть переопределено в производном классе путем включения объявления свойства, использующего модификатор override.»?

(это 2-е различие между виртуальным и абстрактным)

спасибо заранее, George

Ответы [ 5 ]

10 голосов
/ 03 марта 2009

Единственное различие между виртуальным и абстрактным заключается в том, что абстрактный метод или свойство не имеют реализации в классе, в котором он был определен (абстрактный класс), и что он должен быть переопределен в подклассе. ; тогда как виртуальный метод или свойство имеет реализацию в классе, где он был определен, и поэтому не обязательно переопределять его в подклассе.

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;
       }
}
6 голосов
/ 16 апреля 2009

Я могу понять путаницу. Я был там раньше, поэтому я поделюсь, как я сохраню основные различия ...

virtual против abstract:

  • Если метод класса (или свойство) отмечен virtual, тогда может быть переопределено с помощью override ключевое слово, если вы решите наследовать (также известный как * * * *) из этого класса.

    Ключевое слово virtual предназначено, чтобы вызвать идею о том, что метод может быть или не быть фактическим вызванным методом. Поэтому я всегда думаю о virtual членах как о реализациях по умолчанию , что означает, что он представляет функциональность, которая может быть обобщена, например, метод Eat() в классе Human, который может включать прием пищи Руки. Однако класс ChineseHuman может переопределить реализацию по умолчанию из Eat(), чтобы можно было реализовать реализацию, в которой вместо этого используются палочки. Наконец, поскольку виртуальные методы и свойства являются реализациями по умолчанию , класс, который определяет этот член, должен обеспечивать полную реализацию метода или свойства. Все Human объекты должны знать, как Eat().

    Объектно-ориентированное мышление может заявить, что virtual члены представляют инстинкты . К Eat() относится инстинкт объекта класса Human. A ChineseHuman может учиться до Eat() с палочками.

  • Если метод класса (или свойство) отмечен abstract, тогда он должен быть переопределенным с помощью override ключевое слово, если вы решите наследовать из этого класса.

    Ключевое слово abstract предназначено, чтобы вызвать идею о том, что только класс поддерживает возможность, представленную членом, и что нет какой-либо общей логики, которая может быть обобщено для этой функции. Другими словами, abstract члены являются только концептуальными , и поэтому им не хватает реализации. Немного сбивает с толку, что C # просит нас override абстрактных членов, когда мы реализуем отношения наследования, но в этом случае это действительно означает, что мы переопределяем пустую концепцию с конкретной реализацией. Примером abstract члена класса Human может быть 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() является Human, а EnglishHuman и ChineseHuman оба также наследуются от Human, EnglishHuman может наследоваться от BabyHuman вместо Human. Быть Human - это abstract, потому что мы все нечто большее, чем просто Human.
  • abstract члены не могут быть скрыты, могут быть только их реализации override (далее по цепочке наследования). Например, BabyHuman должен реализовывать метод abstract Speak() как override. Если EnglishHuman наследуется от BabyHuman, он может затем скрыть реализацию BabyHuman Speak() со своей собственной реализацией, используя ключевое слово new (см. Ниже ссылку «Скрытие метода в C #»).
  • abstract классы могут иметь virtual членов. Это главное различие между классами interface и abstract. В этом смысле класс abstract может определять как контракт, так и шаблон поведения класса, тогда как interface определяет только контракт.

Код ссылки:

1 голос
/ 03 марта 2009

Хорошо, допустим, у вас есть базовый класс, и этот базовый класс сам по себе является производным от другого класса.

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

Что означает виртуальное ключевое слово, так это то, что в классе, производном от 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. Если вы определите SomeProperty в Baz как виртуальный, классы, производные от Baz, также могут переопределить его (на самом деле, это может потребоваться - не могу вспомнить сразу же).

Дальнейшее уточнение: Абстрактный метод не имеет реализации; когда вы добавляете один в свой класс, вы также должны пометить класс как абстрактный, и вы не можете создавать новые экземпляры этого класса, например:

MyAbstractType m = new MyAbstractType();

Виртуальные члены, с другой стороны, могут иметь реализацию (например, SomeProperty, выше), поэтому вам не нужно отмечать абстрактный класс, и вы можете создавать его экземпляры.

1 голос
/ 03 марта 2009

Если вы объявите метод виртуальным в базовом классе, вы можете переопределить его в производном классе.

Пример

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

}

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

Обратите внимание на модификатор переопределения в MyDerivedClass.

1 голос
/ 03 марта 2009

Можете ли вы объяснить, что смущает? Свойства могут быть переопределены как любой другой метод.

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

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