Почему мы используем виртуальные и переопределяем?

Почему мы используем override и virtual, если он дает тот же эффект, когда мы не используем переопределение и виртуальные?

пример 1:

class BaseClass
{
    public virtual string call()
    {
        return "A";
    }
}

class DerivedClass : BaseClass
{
    public override string call()
    {
        return "B";
    }
}

вывод: B

Пример 2:

class BaseClass
{
    public string call()
    {
        return "A";
    }
}

class DerivedClass : BaseClass
{
    public string call()
    {
        return "B";
    }
}

и вывод все тот же:

вывод: B

для запуска теста:

class Program
{
    static void Main(string[] args)
    {
        DerivedClass dc = new DerivedClass();
        Console.WriteLine(dc.call());
        Console.ReadKey();
    }
}

Является ли компилятор автоматически добавляться и переопределяться во время компиляции?

Я был бы рад, если бы кто-нибудь объяснил мне причину использования виртуальных и переопределить.

Ответы

Ответ 1

(заметьте, я спокойно игнорирую ошибки компиляции)

Теперь выполните:

BaseClass obj = new DerivedClass();
Console.WriteLine(obj.call());

Без virtual, это напечатает A, когда на самом деле a DerivedClass должен писать B. Это связано с тем, что он просто вызвал реализацию BaseClass (поскольку obj набирается как BaseClass, и никакой полиморфизм не определен).

Ответ 2

Виртуальное и переопределение являются базовым механизмом наследования в объектно-ориентированном программировании. Это, пожалуй, самое важное для понимания, когда вы используете классы на языке С# или Java.

http://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)

Наследование позволяет повторно использовать код, добавляющий новые поля, свойства и методы или заменяя методы и свойства ранее определенных классов.

Virtual и Override позволяют вам заменять содержимое метода, и когда я говорю "replace", я говорю "replace".

Я бы предложил вам хороший пример.

public class MyClassEnglish
{
    public virtual string SomethingToSay()
    {
        return "Hello!";
    }

    public void WriteToConsole()
    {
        Console.WriteLine(this.SomethingToSay());
    }
}

public class MyClassItalian :
    MyClassEnglish
{
    public override string SomethingToSay()
    {
        return "Ciao!";
    }
}

int main()
{
    MyClassItalian it = new MyClassItalian();

    it.WriteToConsole();
}

Если вы опустите виртуальный и переопределите, MyClassItalian выведет "Hello!" а не "Цяо!".

В вашем примере вы показываете технику Shadowing, но компилятор должен дать вам предупреждение. Вы хотите добавить новое ключевое слово, если хотите скрыть метод в базовом классе. Скрытие метода не переопределяет! Просто скрывается.

Одно из возможных применений, которое приходит мне в голову, заключается в том, что его можно использовать, когда вам нужна какая-то оптимизация, например.

public abstract class MySpecialListBase
{
    public int Count()
    {
        return this.GetCount();
    }

    protected abstract int GetCount();
}

public sealed class MySpecialArrayList : MySpecialListBase
{
    int count;

    public new int Count()
    {
        return this.count;
    }

    protected override int GetCount()
    {
        return this.count;
    }
}

Теперь... Вы можете использовать MySpecialListBase во всем своем коде, а при вызове Count() он вызовет виртуальный метод GetCount(). Но если вы используете только MySpecialArrayList, он вызовет оптимизированный Count(), который не является виртуальным, и который просто возвращает поле, увеличивая производительность.

// This works with all kind of lists, but since it is a more general purpose method it will call the virtual method.    
public void MyMethod(MySpecialListBase list)
{
    Console.WriteLine(list.Count());
}

// This works only with MySpecialArrayList, and will use the optimized method.
public void MyMethod(MySpecialArrayList list)
{
    Console.WriteLine(list.Count());
}

Ответ 3

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

Когда вы добавляете свой объект в combobox, вы хотите иметь возможность контролировать, какой текст отображается для каждого элемента. Object.toString - виртуальный метод. http://msdn.microsoft.com/en-us/library/system.object.tostring.aspx, и из-за этого вы можете переопределить этот метод и установить .toString, чтобы отобразить правильную информацию о вашем объекте, переопределив его.

public MyClass()
{
     private int ID;
     public override string ToString()
     {
         return "My Item:" + ID;
     }
}

Ответ 4

Переопределение метода:

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

Когда вы решите объявить метод как виртуальный, вы даете разрешение производным классам расширять и переопределять метод с их собственной реализацией. Вы можете также использовать расширенный метод для кода родительского метода.

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

С# Переопределение В С# вы указываете виртуальный метод с ключевым словом virtual в родительском классе и расширяете (или заменяете) его в классе потомков, используя ключевое слово переопределения.

Используйте ключевое слово base в методе потомка для выполнения кода в родительском методе, т.е. base.SomeMethod().

Пример синтаксиса:

class Robot
{
  public virtual void Speak()
  {
  }
}

class Cyborg:Robot
{
   public override void Speak()
   {
   }
}

Сведения о переопределении Вы не можете переопределить обычный не виртуальный метод, а также статический метод. Первая версия родительского метода должна быть виртуальной или абстрактной. Вы можете переопределить любой родительский метод, помеченный как виртуальный, абстрактный, так и переопределенный (уже переопределенный). Методы должны иметь одну и ту же подпись. Методы должны иметь одинаковую видимость (одинаковый уровень доступа). Используйте ключевое слово base для обращения к родительскому классу, как в base.SomeMethod(). Пример переопределения С# Следующий фрагмент кода демонстрирует использование virtual и override для переопределения родительского метода в классе потомков.

using System;

class Dog
{
   public virtual void Bark()
   {
       Console.WriteLine("RUFF!");
   }
}

class GermanShepard:Dog
{
    public override void Bark()
    {
       Console.WriteLine("Rrrrooouuff!!");
    }
}

class Chiuaua:Dog
{
    public override void Bark()
    {
         Console.WriteLine("ruff");
    }
}
class InclusionExample
{
     public static void Main()
     {
        Dog MyDog=new Dog();    
        MyDog=new GermanShepard();
        MyDog.Bark(); // prints Rrrrooouuff!!

        MyDog=new Chiuaua();
        MyDog.Bark(); // prints ruff;
    }
}

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

Новые и переопределяющие модификаторы имеют разные значения. Новый модификатор создает новый элемент с тем же именем, подписью и видимостью и скрывает исходный элемент. Модификатор переопределения расширяет реализацию для унаследованного элемента и позволяет реализовать полиморфизм на основе наследования.

Избегайте появления новых членов: иногда есть явные причины для внедрения нового метода с тем же именем, сигнатурой и видимостью родительского метода. В этих очевидных случаях введение нового участника является мощной функцией. Однако, если у вас нет ясной причины, то не следует вводить новую версию метода, называя новый метод чем-то уникальным и подходящим.

class Robot : System.Object
{
  public void Speak()
  {
    MessageBox.Show("Robot says hi");
  }
}

class Cyborg : Robot
{
  new public void Speak()
  {
    MessageBox.Show("hi");
  }
}

Вызов базовой версии класса Общая задача. В OO необходимо расширить метод, сначала выполнив код родительского метода, а затем добавив код. Используйте ключевое слово base, чтобы ссылаться на родительский класс как на base.SomeMethod().

class Robot : System.Object
{
    public virtual void Speak()
    {
       MessageBox.Show("Robot says hi");
    }
}
class Cyborg : Robot
{
  public override void Speak()
  {
      base.Speak(); 
      MessageBox.Show("hi");
  }
}