Лабораторная работа № 2

Создание объектов

1. Цель работы. Получение навыков в разработке программ с использованием объектов.

Общие сведения

Класс предоставляет компилятору все необходимые сведения для создания создания объекта данного класса. В то же время в реальной программе могут действовать только объекты. Как только определен класс, можно создать объект этого типа, используя имя класса. Фактически имя класса становится спецификатором нового типа данных. Например, следующий код создает объект с именем intqueue типа queue: queue intqueue.

Для создания объекта каждый класс автоматически снабжается одноименным методом без параметров, который называется конструктором по умолчанию. Задача конструктора заключается в выделении объекту динамической памяти, необходимой для размещения всех его полей. При обращении к конструктору используется зарезервированное слово new. Возможные варианты создания объектов показаны здесь:

using System;

{ class queue

{private int q=50;

private char[] arrchar= new char[4] {'a','b','c','d'};

public int p = q;

public char ch = arrchar[0];

}

class Executer

{ [STAThread]

static void Main()

{ //Новый объект можно создать в одной строке:

queue a = new queue(); // создание объекта a класса queue

// ... или двух

queue b;

b = new queue(); // создание объекта b класса queue

}

}

}

Если рассматривается та часть программы, которая не входит в состав класса, то для вызова переменной класса необходимо использовать имя объекта и оператор «точка». Например, следующий фрагмент иллюстрирует вызов переменной p для объекта а и переменной ch для объекта b:

using System;

{ class queue

...

...

queue a = new queue(); // создание объекта a класса queue

queue b;

b = new queue(); // создание объекта b класса queue

Console.WriteLine(a.p); // Вызов значения переменной p

Console.WriteLine(b.ch); // Вызов значения переменной ch

Console.ReadLine(); // Ожидание нажатия клавиши Enter

}

}

}

Очень важно ясно себе представлять, что а и b являются двумя различными объектами. Это означает, что инициализация а не означает инициализацию b. Единственной связью между объектами а и b служит то, что они являются объектами одного и того же типа. Более того, копии переменных q, char, p и ch объекта а совершенно независимы от соответствующих копий переменных объекта b.

Использование имени класса и оператора «точка» необходимо только при вызове переменных или функций извне класса. Внутри класса одна переменная или функция может вызывать другую переменную или функцию непосредственно без использования оператора «точка».

Умалчиваемый конструктор, как и любой другой метод класса, можно перегрузить. Перегрузка метода заключается в том, что в классе объявляется одноименный метод. Чтобы компилятор «понял», о каком методе идет речь, набор входных параметров перегруженного метода (с учетом полиморфизма) должен отличаться от параметров оригинального — это обязательное условие. При необходимости можно сколько угодно раз перегружать метод, лишь бы у всех перегруженных методов наборы входных параметров отличались друг от друга и от параметров оригинального метода.

Полиморфизм — это принцип автоматического выбора метода, вызываемого объектом, в соответствии с типом данного объекта и с учетом иерархии наследования.

Программа реализующая перегрузку умалчиваемого конструктора представлена в следующем листинге:

using System;

namespace Project2

{ class queue

{ private int q=50;

private char[] arrchar= new char[4] {'a','b','c','d'};

public int p;

public char ch;

public queue() {} // Конструктор по умолчанию

public queue(int q, int i) // Перегруженный конструктор

{ p = q;

ch = arrchar[i];

}

}

class Executer

{

[STAThread]

static void Main()

{

// Создание объекта a с помощью перегруженного конструктора

queue a = new queue(500,1);

Console.WriteLine(a.p);

Console.WriteLine(a.ch);

// Создание объекта b с помощью конструктора по умолчанию

queue b = new queue();

Console.WriteLine(b.p);

Console.WriteLine(b.ch);

Console.ReadLine(); // Ожидание нажатия клавиши Enter

}

}

}

Постановка задачи

Создать объекты класса <имя класса> (класс и его поля задаются в соответствии с выбранным вариантом в лабораторной работе 1). Объекты должны быть созданы с помощью конструктора по умолчанию и перегруженного конструктора.

Порядок выполнения работы

В главном меню системы программирования выберите команду FileNewProject или щелкните на соответствующей инструментальной кнопке. В окне New Project выберите пункт Console Application и щелкните на кнопке OK. В открывшемся окне в соответствии с вариантом задания напишите программу, использующую созданные вами объекты.

Содержание отчета

5.1 Тема и цель работы.

5.2 Текст программы.

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

Лабораторная работа № 3

Наследование, скрытие полей класса и виртуальные методы

1. Цель работы. Получение навыков в разработке программ с использованием классов образованных от других классов.

Общие сведения

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

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

Например, описан класс queue1, наследующий описание класса queue:

using System;

{ class queue1 : queue

{ }

}

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

Скрытие (переопределение) элементов класса — это явное описание в классе наследнике с новыми характеристиками уже существующих элементов из наследуемого класса.

Следующий пример иллюстрирует переопределение в классе queue1, наследуемому от класса queue, полей q и arrchar с невидимых в видимые и присвоению им новых значений, а также введение в класс queue1 новой переменной r.

using System;

namespace Project3

{

class queue

{ private int q=50;

private char[] arrchar= new char[4] {'a','b','c','d'};

public int p;

public char ch;

}

class queue1 : queue

{ private int r = 50;

public new int q=50;

public new char[] arrchar= new char[4] {'e','f','g','h'};

public queue1() {}

public queue1(int q, int i)

{ p = q*r;

ch = arrchar[i]; }

}

class Executer

{

static void Main()

{

//В переменную a наследуемого класса записывают экземпляр класса-наследника:

queue a = new queue1(500,1);

// Создание объекта b класса queue1

queue1 b = new queue1(50,2);

Console.WriteLine(a.p);

Console.WriteLine(a.ch);

Console.WriteLine(b.p);

Console.WriteLine(b.ch);

Console.ReadLine();

}

} }

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

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

Следующий пример иллюстрирует данную возможность.

using System;

namespace Project3a

{ class Roditel

{ public virtual string GetStr() {return "Родитель";}

public void Test() {Console.WriteLine(GetStr());}

}

class Naslednik : Roditel

{ public override string GetStr() {return "Наследник";}

}

class Executer

{ static void Main()

{ Roditel A = new Roditel();

Naslednik B = new Naslednik();

A.Test(); // Вывод: Родитель

B.Test(); // Вывод: Наследник

Console.ReadLine(); }

}

}

Постановка задачи

Создать класс-наследник от класса <имя класса> (класс и его поля задаются в соответствии с выбранным вариантом в лабораторной работе 1). В классе-наследнике перекрыть некоторые поля класса-родителя и добавить дополнительное поле, связанное со свойствами предмета задания по варианту. При перекрывании полей использовать виртуальные методы. Создать объекты обоих полученных класса и занести в них данные. Организовать обращения родительских методов к замещающим их методам наследника.

Наши рекомендации