Переопределение виртуальных методов в обобщенных классах. Примеры
Перед изучением данной темы рекомендуется ознакомиться со следующими темами:
- Иерархии обобщенных классов. Обобщенный базовый и производный классы
- Позднее и раннее связывание. Полиморфизм. Основные понятия. Примеры. Передача в метод ссылки на базовый класс. Ключевые слова virtual, override, new
Содержание
- 1. Переопределение виртуальных методов в обобщенных классах. Особенности. Синтаксис
- 2. Пример, демонстрирующий переопределение методов в обобщенных классах, образующих иерархию. Классы получают параметром тип T
- 3. Пример переопределения виртуальных методов для базового и производного классов, получающих параметрами два типа T1, T2
- Связанные темы
Поиск на других ресурсах:
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 ConsoleApp19 { 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 = $
⇑
Связанные темы
- Позднее и раннее связывание. Полиморфизм. Основные понятия. Примеры. Передача в метод ссылки на базовый класс. Ключевые слова virtual, override, new
- Обобщения. Основные понятия. Обобщенные классы и структуры
- Иерархии обобщенных классов. Обобщенный базовый и производный классы
⇑