Шаг 164.
Язык программирования C#. Начала
Абстрактные классы и интерфейсы. Примеры использования
На этом шаге мы рассмотрим несколько примеров решения задач, в которых используются абстрактные классы и интерфейсы.
Здесь мы рассмотрим несколько программ, в которых используются ранее рассмотренные абстрактные классы и интерфейсы.
Задание 1.
Напишите программу, содержащую абстрактный базовый класс с защищенным полем, являющимся ссылкой на целочисленный массив. У класса должен быть конструктор с одним аргументом
(определяет размер массива и создает его), целочисленное свойство (значение - размер массива), абстрактный метод (без аргументов, не возвращает результат) и индексатор с целочисленным
индексом (доступен для чтения и записи). В производном классе описать абстрактный метод из базового класса, чтобы он отображал в консоли содержимое массива. Индексатор определить так,
чтобы с его помощью можно было прочитать значение элемента массива и присвоить значение элементу массива.
Раскрыть/скрыть решение и комментарии.
В условии задачи полностью описано, какой должен быть класс, что в нем должно быть реализовано. Надеемся, что приведенных комментариев будет достаточно для понимания ее работы.
Обратите внимание, что для опеределения размерности массива и его заполнения, используется генератор псевдослучайных чисел.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace pr164_1
{
// Абстрактный класс:
abstract class Base
{
// Защищенное целочисленное поле
// (указатель на целочисленный массив):
protected int[] mas;
// Конструктор:
public Base(int len)
{
// Создание массива указанной размерности
mas = new int[len];
// Объект для генерирования случайных чисел:
Random rnd = new Random();
for (int i = 0; i < len; i++)
{
// Значение элемента массива:
mas[i] = rnd.Next(20);
}
}
// Целочисленное свойство:
public int len_mas
{
// Возвращает размер массива
get
{
return mas.Length;
}
}
// Абстрактный метод:
// выводит содержимое массива
public abstract void show();
// Абстрактный индексатор с целочисленным индексом:
public abstract int this[int k]
{
get;
set;
}
}
// Производный класс на основе абстрактного:
class MyClass: Base {
// Конструктор
public MyClass(int n) : base(n) { }
// Переопределение абстрактного метода:
public override void show()
{
for(int k = 0;k < mas.Length; k++) {
Console.Write("|" + mas[k]);
}
Console.WriteLine("|");
}
// Переопределение индексатора:
public override int this[int k]
{
get
{
// Значение элемента числового массива:
return mas[k];
}
set
{
// Присваивание значения элементу числового массива:
mas[k] = value;
}
}
}
class Program
{
static void Main()
{
// Объект для генерирования случайных чисел:
Random rnd = new Random();
// Создание объекта:
MyClass obj = new MyClass(rnd.Next(20));
// Вывод массива объекта:
Console.WriteLine("Исходный массив:");
obj.show();
// Вывод размера массива:
Console.WriteLine("Размер массива = " + obj.len_mas);
// Читаем значение элемента:
int nom = rnd.Next(5);
Console.WriteLine("Элемент obj[" + nom + "] = " + obj[nom]);
// Меняем значение элемента:
obj[nom] = rnd.Next(20);
// Снова выводим массив объекта:
Console.WriteLine("Массив с измененным " + nom + "-м элементом:");
obj.show();
// Задержка:
Console.ReadLine();
}
}
}
Архив проекта можно взять
здесь.
Результат работы приложения приведен на рисунке 1.
Рис.1. Результат работы приложения
Задание 2.
Напишите программу, содержащую абстрактный класс с двумя защищенными целочисленными полями и конструктор с двумя целочисленными аргументами. В классе должен быть объявлен
абстрактный индексатор с целочисленным индексом. Опишите интерфейс, в котором есть метод с целочисленным аргументом и целочисленным результатом. Опишите класс, который наследует
абстрактный базовый класс и реализует интерфейс. В этом классе опишите индексатор так, чтобы при четном индексе выполнялось обращение к первому полю, а при нечетном индексе обращение
выполнялось ко второму полю. Метод следует описать таким образом, чтобы он результатом возвращал сумму значений полей, умноженную на аргумент метода.
Раскрыть/скрыть решение и комментарии.
Решение этой задачи аналогично предыдущей: в условии сказано: что, где и как создавать. Реализация этой программы не должна вызвать затруднений. Единственное, на что
требуется обратить внимание (впрочем, как и при решении первой задачи), это на использование служебногог слова override при реализации методов и индексаторов
абстрактного класса.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace pr164_2
{
// Абстрактный класс:
abstract class Base
{
// Защищенные целочисленные поля:
protected int num1;
protected int num2;
// Конструктор с двумя аргументами:
public Base(int n1, int n2)
{
num1 = n1;
num2 = n2;
}
// Абстрактный индексатор с целочисленным индексом:
public abstract int this[int k]
{
get;
}
}
// Интерфейс:
interface MyInterface
{
// Объявление метода:
int setNum(int n);
}
// Производный класс наследует абстрактный базовый класс
// и реализует интерфейс:
class MyClass: Base, MyInterface
{
// Конструктор с двумя аргументами:
public MyClass(int n1, int n2) : base(n1, n2) { }
// Явная реализация индексатора из
// абстрактного класса:
public override int this[int k]
{
get
{
if (k % 2 == 0)
return num1;
else
return num2;
}
}
// Описание метода из интерфейса:
public int setNum(int n)
{
return n * (num1 + num2);
}
}
class Program
{
static void Main()
{
// Создание объекта:
MyClass obj = new MyClass(2, 5);
// Вызов индексатора:
Console.WriteLine("obj[1] = " + obj[1]);
Console.WriteLine("obj[2] = " + obj[2]);
Console.WriteLine("obj.setNum(3) = " + obj.setNum(3));
// Задержка:
Console.ReadLine();
}
}
}
Архив проекта можно взять
здесь.
Результат работы приложения изображен на рисунке 2.
Рис.2. Результат работы приложения
Задание 3.
Напишите программу, содержащую абстрактный класс и два интерфейса. Класс должен содержать объявление абстрактного свойства (с двумя аксессорами), абстрактного индексатора (с двумя
аксессорами) и абстрактного метода. Такое же свойство, индексатор и метод должны быть в интерфейсах. На основе абстрактного класса и интерфейсов необходимо создать класс. В этом классе
необходимо выполнить явную реализацию для свойства, индексатора и метода для каждого из интерфейсов. Проверьте работу свойства, индексатора и метода, получив доступ к объекту класса
через объектную переменную и через интерфейсные переменные.
Раскрыть/скрыть решение и комментарии.
За основу реализации мы взяли программу из 162 шага и дополнили ее недостающими конструкциями. Ее полный текст приведен ниже.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace pr164_3
{
// Базовый класс:
abstract class Base
{
// Абстрактное свойство:
public abstract char symbol
{
get;
set;
}
// Абстрактный индексатор:
public abstract int this[int k]
{
get;
set;
}
// Абстрактный метод:
public abstract void show();
}
// Первый интерфейс:
interface First
{
// Свойство:
char symbol
{
get;
set;
}
// Индексатор:
int this[int k]
{
get;
set;
}
// Метод:
void show();
}
// Второй интерфейс:
interface Second
{
// Свойство:
char symbol
{
get;
set;
}
// Индексатор:
int this[int k]
{
get;
set;
}
// Метод:
void show();
}
// Производный класс наследует абстрактный базовый класс
// и реализует интерфейсы:
class MyClass: Base, First, Second
{
// Закрытое символьное поле:
private char smb;
// Конструктор с символьньм аргументом:
public MyClass(char s): base()
{
smb = s;
}
// Описание свойства из абстрактного класса:
public override char symbol
{
get
{
return smb;
}
set
{
smb = value;
}
}
// Явная реализация свойства из интерфейса First:
char First.symbol
{
get
{
return (char)(smb + 1);
}
set
{
smb = (char)(value + 1);
}
}
// Явная реализация свойства из интерфейса Second:
char Second.symbol
{
get
{
return (char)(smb + 2);
}
set
{
smb = (char)(value + 2);
}
}
// Описание индексатора из базового класса:
public override int this[int k]
{
get
{
return smb + k;
}
set
{
smb = (char)(value + k % 2);
}
}
// Явная реализация индексатора из интерфейса First:
int First.this[int k]
{
get
{
return smb + k / 2;
}
set
{
smb = (char)(value - k % 2);
}
}
// Явная реализация индексатора из интерфейса Second:
int Second.this[int k]
{
get
{
return smb + k / 2 + 1;
}
set
{
smb = (char)(value - k % 2 + 1);
}
}
// Описание метода из базового класса:
public override void show()
{
Console.WriteLine("Базовый класс Base:\t\'{0}\'", symbol);
}
// Явная реализация метода из интерфейса First:
void First.show()
{
Console.WriteLine("Интерфейс First:\t\'{0}\'", symbol);
}
// Явная реализация метода из интерфейса Second:
void Second.show()
{
Console.WriteLine("Интерфейс Second:\t\'{0}\'", symbol);
}
}
// Класс с главным методом:
class Program
{
static void Main()
{
// Создание объекта:
MyClass obj = new MyClass('A');
// Интерфейсные переменные:
First A = obj;
Second B = obj;
// Вызов метода через переменные:
obj.show();
A.show();
B.show();
// Считывание значения свойства:
Console.WriteLine("obj.symbol = \'{0}\'", obj.symbol);
Console.WriteLine(" A.symbol = \'{0}\'", A.symbol);
Console.WriteLine(" B.symbol = \'{0}\'", B.symbol);
// Индексирование объекта:
Console.WriteLine("obj[10] = {0}", obj[10]);
Console.WriteLine(" A[10] = {0}", A[10]);
Console.WriteLine(" B[10] = {0}", B[10]);
// Присваивание значений:
obj[10] = 5;
A[10] = 2;
B[10] = 3;
// Индексирование объекта:
Console.WriteLine("obj[10] = {0}", obj[10]);
Console.WriteLine(" A[10] = {0}", A[10]);
Console.WriteLine(" B[10] = {0}", B[10]);
// Задержка:
Console.ReadLine();
}
}
}
Архив проекта можно взять
здесь.
Результат работы приложения изображен на рисунке 3.
Рис.3. Результат работы приложения
Попробуйте разобраться с ней самостоятельно.
На следующем шаге мы начнем знакомиться с делегатами и событиями.
Предыдущий шаг
Содержание
Следующий шаг