C#. Перевизначення віртуальних методів в узагальнених класах

Перевизначення віртуальних методів в узагальнених класах. Приклади

Перед вивченням даної теми рекомендується ознайомитись з наступними темами:


Зміст


Пошук на інших ресурсах:




1. Перевизначення віртуальних методів в узагальнених класах. Особливості. Синтаксис

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

Метод, що оголошується в базовому класі як віртуальний, повинен бути оголошений з модифікатором virtual. Однойменні методи в успадкованих класах оголошуються з модифікатором override.

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

Якщо не потрібно, щоб метод у похідному класі перевизначав метод базового класу та розглядався як невіртуальний (не підтримує механізм поліморфізму), то такий метод оголошується з модифікатором new або без модифікатора.

Якщо два узагальнені класи, що отримують параметром тип T, утворюють ієрархію, то загальна форма оголошення віртуального методу в базовому класі наступна

class Base<T>
{
  ...

  public virtual VirtualMethodName(parameters)
  {
    ...
  }

  ...
}

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

class Derived<T> : Base<T>
{
  ...

  public override VirtualMethodName(parameters)
  {
    ...
  }

  ...
}

 

2. Приклад, що демонструє перевизначення методів в узагальнених класах, що утворюють ієрархію. Класи отримують параметром тип T

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

Оголошується базовий узагальнений клас Base<T>, який отримує параметром тип T і має наступні складові:

  • поле value узагальненого типу T, що визначає дані класу;
  • конструктор з одним параметром;
  • віртуальні методи доступу GetValue(), SetValue(). Ці методи оголошуються з модифікатором virtual;
  • віртуальний метод PrintValue(), який виводить значення внутрішнього поля value.

Також оголошується узагальнений клас Derived<T>, що успадкований від класу Base<T>. Клас містить наступні поля та методи:

  • внутрішнє поле value узагальненого типу T;
  • конструктор, що викликає конструктор базового класу;
  • віртуальні методи GetValue(), SetValue(), які перевизначають однойменні методи класу Base<T>. Ці методи оголошені з ключовим словом override;
  • віртуальний метод PrintValue(), який перевизначає однойменний метод базового класу. Метод оголошується з модифікатором virtual.

 

using System;

namespace ConsoleApp1
{
  class Base<T>
  {
    // Внутрішні дані
    T value;

    // Конструктор
    public Base(T _value)
    {
      Console.WriteLine("Constructor Base(T)");
      value = _value;
    }

    // Методи доступу до value - віртуальні
    public virtual T GetValue()
    {
      Console.WriteLine("Base.GetValue()");
      return value;
    }

    public virtual void SetValue(T _value)
    {
      Console.WriteLine("Base.SetValue()");
      value = _value;
    }

    // Віртуальний метод, що виводить значення value
    // з класу Base
    public virtual void PrintValue(string message)
    {
      Console.WriteLine(message);
      Console.WriteLine("Base.value = " + value);
    }
  }

  // Похідний клас, який має власні методи,
  // імена яких співпадають з іменами базового класу Base<T>
  class Derived<T> : Base<T>
  {
    // Внутрішнє поле з іменем value
    T value;

    // Конструктор, обов'язково повинен
    // викликати конструктор базового класу
    public Derived(T valueBase, T valueDerived) : base(valueBase)
    {
      Console.WriteLine("Constructor Derived(T)");
      value = valueDerived;
    }

    // Методи доступу - перевизначають методи доступу базового класу
    public override T GetValue()
    {
      Console.WriteLine("Derived.GetValue()");
      return value;
    }

    public override void SetValue(T _value)
    {
      Console.WriteLine("Derived.SetValue()");
      value = _value;
    }

    // Метод, що перевизначає віртуальний метод базового класу
    public override void PrintValue(string message)
    {
      base.PrintValue(message);
      Console.WriteLine("Derived.value = " + value);
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. Створити екземпляр базового класу
      Base<double> obj1 = new Base<double>(2.88);
      obj1.PrintValue("obj1:");

      // Викликати методи базового класу
      obj1.SetValue(11.77);
      Console.WriteLine("value = " + obj1.GetValue());
      Console.WriteLine("--------------------");

      // 2. Створити екземпляр похідного класу
      Derived<int> obj2 = new Derived<int>(10, 20);
      obj2.PrintValue("obj2:");

      // Викликати методи похідного класу
      obj2.SetValue(35);
      obj2.PrintValue("obj2:");

      Console.ReadKey();
    }
  }
}

Результат виконання програми

Constructor Base(T)
obj1:
Base.value = 2.88
Base.SetValue()
Base.GetValue()
value = 11.77
--------------------
Constructor Base(T)
Constructor Derived(T)
obj2:
Base.value = 10
Derived.value = 20
Derived.SetValue()
obj2:
Base.value = 10
Derived.value = 35

 

3. Приклад перевизначення віртуальних методів для базового та похідного класів, що отримують параметрами два типи T1, T2

У прикладі продемонстровано:

  • використання механізму спадковості для оголошення узагальнених класів, що утворюють ієрархію;
  • оголошення базового та похідного узагальнених класів, які отримують параметрами два типи T1, T2;
  • виклик конструктору базового класу з успадкованого класу у випадку узагальнень;
  • перевизначення віртуальних методів базового класу з метою забезпечення поліморфізму;
  • звертання до полів базового класу з успадкованого класу з допомогою засобу base.

Оголошується два узагальнені класи, які отримують параметрами типи T1, T2. Класи утворюють ієрархію. Один з класів є базовий, інший – похідний (успадкований).

Узагальнений базовий клас A<T1, T2> містить наступні елементи:

  • внутрішні поля a1, a2, що мають відповідно типи T1, T2;
  • конструктор з двома параметрами, який ініціалізує значеннями поля a1, a2;
  • віртуальні методи читання полів a1, a2 з іменами GetA1(), GetA2(). Ці методи оголошено з модифікатором virtual;
  • методи запису нових значень в поля a1, a2 з іменами SetA1(), SetA2(). Ці методи оголошено з модифікатором virtual.

З класу A<T1, T2> успадкований клас B<T1, T2>, який не містить внутрішніх полів, а містить наступні методи:

  • конструктор з двома параметрами. Даний конструктор викликає конструктор базового класу з допомогою ключового слова base;
  • віртуальні методи для читання значень полів a1, a2 базового класу. Методи мають такі самі назви як методи базового класу: GetA1(), GetA2(). Це означає, що вони перевизначають методи базового класу. Для забезпечення поліморфізму методи оголошено з ключовим словом override. У методах здійснюється виклик однойменних методів базового класу з допомогою ключового слова base;
  • віртуальні методи SetA1(), SetA2() для запису нових значень в поля a1, a2 базового класу. Робота методів у класі аналогічна методам GetA1(), GetA2().

Нижче наведено текст демонстраційної програми

using System;

namespace ConsoleApp1
{
  class A<T1, T2>
  {
    // Внутрішні дані
    T1 a1;
    T2 a2;

    // Конструктор
    public A(T1 _a1, T2 _a2)
    {
      a1 = _a1;
      a2 = _a2;
    }

    // Методи доступу до a1, a2
    public virtual T1 GetA1()
    {
      return a1;
    }

    public virtual T2 GetA2()
    {
      return a2;
    }

    public virtual void SetA1(T1 a1)
    {
      this.a1 = a1;
    }

    public virtual void SetA2(T2 a2)
    {
      this.a2 = a2;
    }
  }

  // Похідний клас, який має власні методи,
  // імена яких співпадають з іменами базового класу A<T1, T2>
  class B<T1, T2> : A<T1,T2>
  {
    // Конструктор, обов'язково повинен
    // викликати конструктор базового класу
    public B(T1 a1, T2 a2) : base(a1, a2)
    { }

    // Методи доступу - перевизначають методи доступу базового класу,
    // ключове слово override дозволяє використовувати механізм поліморфізму.
    public override T1 GetA1()
    {
      // Викликати метод базового класу
      return base.GetA1();
    }

    public override T2 GetA2()
    {
      // Викликати метод базового класу
      return base.GetA2();
    }

    public override void SetA1(T1 a1)
    {
      // Викликати метод базового класу
      base.SetA1(a1);
    }

    public override void SetA2(T2 a2)
    {
      // Викликати метод базового класу
      base.SetA2(a2);
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. Створити екземпляр базового класу
      A<double, int> obj1 = new A<double, int>(2.55, 13);

      // Вивести дані з obj1
      Console.WriteLine("obj1.a1 = " + obj1.GetA1());
      Console.WriteLine("obj1.a2 = " + obj1.GetA2());

      // 2. Створити екземпляр похідного класу
      B<float, char> obj2 = new B<float, char>(3.8f, 'X');

      // Вивести дані з obj2
      Console.WriteLine("obj2.a1 = " + obj2.GetA1());
      Console.WriteLine("obj2.a2 = " + obj2.GetA2());

      // Змінити дані в obj2
      obj2.SetA1(100.05f);
      obj2.SetA2('$');
      Console.WriteLine("The data in the object has been changed.");
      Console.WriteLine("obj2.a1 = " + obj2.GetA1());
      Console.WriteLine("obj2.a2 = " + obj2.GetA2());

      Console.ReadKey();
    }
  }
}

Результат виконання програми

obj1.a1 = 2.55
obj1.a2 = 13
obj2.a1 = 3.8
obj2.a2 = X
The data in the object has been changed.
obj2.a1 = 100.05
obj2.a2 = $

 


Споріднені теми