Що таке віртуальні методи?


81

Чому ви оголошуєте метод "віртуальним"?

Яка вигода від використання віртуального?

Відповіді:


58

Віртуальний модифікатор використовується для позначення , що метод \ властивість (ЕСТ) може бути змінено в похідному класі за допомогою перевизначення модифікатора.

Приклад:

class A
{
    public virtual void Foo()
       //DoStuff For A
}

class B : A
{
    public override void Foo()
    //DoStuff For B

    //now call the base to do the stuff for A and B 
    //if required
    base.Foo()
}

45

Virtual дозволяє класу успадкування замінити метод, який потім використовує базовий клас.

public class Thingy
{
    public virtual void StepA()
    {
        Console.Out.WriteLine("Zing");
    }

    public void Action()
    {
        StepA();
        Console.Out.WriteLine("A Thingy in Action.");
    }
}

public class Widget : Thingy
{
    public override void StepA()
    {
        Console.Out.WriteLine("Wiggy");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Thingy thingy = new Thingy();
        Widget widget = new Widget();

        thingy.Action();
        widget.Action();

        Console.Out.WriteLine("Press any key to quit.");
        Console.ReadKey();
    }
 }

Коли ви запускаєте програму, ваш результат буде:

Zing 
A Thingy in Action. 
Wiggy 
A Thingy in Action.

Зверніть увагу, навіть якщо Widget називав метод Action (), визначений на рівні Thingy, внутрішньо Thingy називав метод StepA () Widget.

Основна відповідь - це дає спадкоємцям класу більшу гнучкість. Звичайно, ви повинні добре розробити свій клас, інакше це може спричинити слабкі руйнування.


23

Віртуальний метод - це тип методу, де фактичні виклики методів залежать від типу виконання базового об'єкта.

Невіртуальний метод - це тип методу, де фактично викликаний метод залежить від посилального типу об’єкта в точці виклику методу.


Це має бути відповіддю - віртуальний не може бути визначений за умови модифікації декларації. Чим він тоді відрізняється від методу приховування?
SENya

13

Віртуальні методи на MSDN

Віртуальне ключове слово використовується для модифікації методу або оголошення властивості, і в цьому випадку метод або властивість називається віртуальним членом. Реалізація віртуального члена може бути змінена головним членом у похідному класі.

Коли викликається віртуальний метод, тип часу виконання об’єкта перевіряється на заміщення члена. Викликається переважний член у найбільш похідному класі, який може бути вихідним членом, якщо жоден похідний клас не перевизначив його. (Для отримання додаткової інформації про тип виконання та найбільш похідну реалізацію див. 10.5.3 Віртуальні методи.)

За замовчуванням методи невіртуальні. Ви не можете замінити невіртуальний метод.

Ви не можете використовувати віртуальний модифікатор із такими модифікаторами:

перевизначення статичного абстрактного

Віртуальні властивості поводяться як абстрактні методи, за винятком відмінностей у декларації та синтаксисі виклику.

  • Помилкою є використання віртуального модифікатора для статичного властивості.
  • Віртуальне успадковане властивість можна замінити у похідному класі, включивши декларацію властивості, яка використовує модифікатор заміни.

6

Навіть якщо ви не плануєте походити з класу, позначення методу віртуальним може знадобитися для того, щоб знущатись над класом. Деякі насмішливі фреймворки дозволяють знущатися лише над віртуальними методами. Зверніть увагу, що методи реалізації інтерфейсу є віртуальними неявно.

Я використовую RhinoMocks, який має це обмеження, і я прийняв позначення моїх методів віртуальними за замовчуванням саме з цієї причини. Для мене це, мабуть, найбільша причина використовувати віртуальні методи, оскільки випадки, коли спадкування вступає в дію, набагато рідше.


5

Віртуальні методи подібні до абстрактних методів у базових класах, за винятком того, що їх реалізація на похідних класах необов’язкова. Також ви можете помістити логіку у віртуальний метод і перевизначити її у похідних класах.


4

Коротке запитання, коротка відповідь! Класифікуйте свій метод як "віртуальний", якщо ви вважаєте, що успадкуєте клас, якому він належить.

Довша відповідь: "віртуальний дозволяє вам перевизначити, щоб надати інше значення вашого методу в похідному класі.


3

Для того, щоб мати можливість замінити це при успадкуванні класів.

Перевірте запис MSDN для ключового слова. Це пояснює це більш глибоко.


1

Зайве говорити, що віртуальні методи стають у нагоді, коли ваш код намагається дотримуватися Відкритого Закритого Принципу

Детальніше про Відкритий Закритий Принцип читайте тут , оригінальний довідник OCP дядька Боба.

Також майте на увазі, що методи за замовчуванням не є віртуальними в C #, на відміну від Java.



1

Віртуальні функції - це функції, яких насправді не існує. Похідний клас може модифікувати віртуальну функцію, перевизначивши її. Віртуальні функції - один із способів досягнення поліморфізму часу виконання

    public class sample {
      public virtual void fun(){
        Console.WriteLine("base sample class \n");
      }
    }
    public class A : sample{
      public override void fun(){
        Console.WriteLine("Class A \n");
      }
    }
    public class B : sample{
      public override void fun(){
        Console.WriteLine("Class B \n");
      }
    }
    class run{
      public static void main(String[] args){
        sample obj = new sample();
        sample obj1 = new A();
        sample obj2 = new B();
        obj.fun();
        obj1.fun();
        obj2.fun();
      }
    }

Що ви маєте на увазі під словом "насправді не існує"? Не могли б ви надати посилання
Мубарек,

Це не схоже на успадкування C #. У publicмодифікатори доступу після class Aі class Bпричини у час компіляції помилок. Доступність членів базового класу з похідного класу визначається на індивідуальній основі від базового класу (за замовчуванням це члени private).
Minh Tran

@Minh Tran - Так, ти маєш рацію. Це було успадкування c ++. Як би там не було, я редагував допис.
Lineesh K Mohan

1

Виконання відбувається протягом часу компіляції.
Коли ви оголошуєте метод віртуальним, для оголошення його у похідному класі потрібно додати overrideабо newмодифікатор.
ми можемо побачити, що коли TrySpeak. Передаючи дитину та батька, обидва називають «Говори про батька», тоді як TryScreamби називали кожен метод.
Щоб це зрозуміти, є деякі речі, які ми повинні знати, наприклад, у випадку Child, є два Screamметоди з класу Child або класу батька. Ми могли зателефонувати Scream з класу Child або класу батька. Оскільки VirtaulМодифікатор позначає метод, щоб він міг бути заміненим похідним класом, що означає, що навіть Screamвиклик із класу батька, він замінений, було б інакше, якщо б ви використовували новий модифікатор.

import system;
class Father
{
    Speak()
    {
        Console.Writeline("Father is speaking") 
    }
    virtual Scream()
    {
        Console.Writeline("Father is screaming")    
    }
}
class Child: father
{
    Speak()
    {
        Console.Writeline("Child is speaking")  
    }
    override Scream()
    {
        Console.Writeline("Child is screaming") 
    }
}
class APP
{
    public static void Main()
    {
        // We new two instances here
        Father father = new Father();
        Child child = new Child();        
        // Here we call their scream or speak through TryScream or TrySpeak
        TrySpeak(father);
        TrySpeak(child);
        //>>>"Father is speaking"
        //>>>"Father is speaking"
        TryScream(father);
        TryScream(child);
        //>>>"Father is screaming"
        //>>>"Child is screaming"
    }
    // when your method take an Parameter who type is Father
    // You can either pass in a Father instance or
    // A instance of a derived Class from Father
    // which could be Child
    public static void TrySpeak(Father person)
    {
        person.Scream();
    }
    public static void TryScream(Father person)
    {
        person.Speak();
    }
}

1

У C # для перевизначення методу базового класу у похідному класі потрібно оголосити метод базового класу як віртуальний, а метод похідного класу - як перевизначений, як показано нижче:

using System;
namespace Polymorphism
{
 class A
 {
 public virtual void Test() { Console.WriteLine("A::Test()"); }
 }

 class B : A
 {
 public override void Test() { Console.WriteLine("B::Test()"); }
 }

 class C : B
 {
 public override void Test() { Console.WriteLine("C::Test()"); }
 }

 class Program
 {
 static void Main(string[] args)
 {

 A a = new A();
 B b = new B();
 C c = new C();
 a.Test(); // output --> "A::Test()"
 b.Test(); // output --> "B::Test()"
 c.Test(); // output --> "C::Test()"

 a = new B();
 a.Test(); // output --> "B::Test()"

 b = new C();
 b.Test(); // output --> "C::Test()"

 Console.ReadKey();
 }
 }
}

Ви також можете змішати приховування методу та перевизначення методу, використовуючи віртуальне та нове ключове слово, оскільки метод похідного класу може бути віртуальним та новим одночасно. Це потрібно, коли ви хочете додатково замінити похідний метод класу на наступний рівень, оскільки я перевизначаю метод B, Test () у класі C, як показано нижче:

using System;
namespace Polymorphism
{
 class A
 {
 public void Test() { Console.WriteLine("A::Test()"); }
 }

 class B : A
 {
 public new virtual void Test() { Console.WriteLine("B::Test()"); }
 }

 class C : B
 {
 public override void Test() { Console.WriteLine("C::Test()"); }
 }

 class Program
 {
 static void Main(string[] args)
 {

 A a = new A();
 B b = new B();
 C c = new C();

 a.Test(); // output --> "A::Test()"
 b.Test(); // output --> "B::Test()"
 c.Test(); // output --> "C::Test()"

 a = new B();
 a.Test(); // output --> "A::Test()"

 b = new C();
 b.Test(); // output --> "C::Test()"

 Console.ReadKey();
 }
 }
}

ЗОЛОТІ СЛОВА: Віртуальне ключове слово використовується для модифікації методу, властивості, індексатора або події, оголошеного в базовому класі, і дозволяє замінити його у похідному класі.

Ключове слово override використовується для розширення або модифікації віртуального / абстрактного методу, властивості, індексатора або події базового класу у похідний клас.

Нове ключове слово використовується для приховування методу, властивості, індексатора або події базового класу у похідному класі.

НАСЛАДУЙСЯ :-)


-1

Це посилання забезпечить вам краще розуміння на дуже простому прикладі https://stackoverflow.com/a/2392656/3373865


1
Це не лише відповідь лише на посилання (будь ласка, включіть у відповідь суть пов’язаного допису на випадок, якщо посилання розірветься), а й про С ++, а не С #. Чи застосовуються тут ті самі принципи?
Marks Polakovs 23.03.18
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.