Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
GEK / ООП_ГОСЫ_ОТВЕТЫ.docx
Скачиваний:
68
Добавлен:
18.05.2015
Размер:
1.83 Mб
Скачать

Роль полиморфизма

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

По сути, виртуальный член — это член базового класса, определяющий реализацию по умолчанию, которая может быть изменена (или, говоря более формально, переопределена) в производном классе. В отличие от него, абстрактный метод — это член базового класса, который не предусматривает реализации по умолчанию, а предлагает только сигнатуру. Когда класс наследуется от базового класса, определяющего абстрактный метод, этот метод обязательно должен быть переопределен в производном классе. В любом случае, когда производные классы переопределяют члены, определенные в базовом классе, они по существу переопределяют свою реакцию на один и тот же запрос.

Рассмотрим для примера стек, т.е. область памяти, функционирующую по принципу "последним пришел — первым обслужен". Допустим, что в программе требуются три разных типа стеков: один — для целых значений, другой — для значений с плавающей точкой, третий — для символьных значений. В данном примере алгоритм, реализующий все эти стеки, остается неизменным, несмотря на то, что в них сохраняются разнотипные данные. В языке, не являющемся объектно-ориентированным, для этой цели пришлось бы создать три разных набора стековых подпрограмм с разными именами. Но благодаря полиморфизму для реализации всех трех типов стеков в С# достаточно создать лишь один общий набор подпрограмм. Зная, как пользоваться одним стеком, вы сумеете воспользоваться и остальными.

В более общем смысле понятие полиморфизма нередко выражается следующим образом: "один интерфейс — множество методов". Это означает, что для группы взаимосвязанных действий можно разработать общий интерфейс. Полиморфизм помогает упростить программу, позволяя использовать один и тот же интерфейс для описания общего класса действий. Выбрать конкретное действие (т.е. метод) в каждом отдельном случае — это задача компилятора. Программисту не нужно делать это самому. Ему достаточно запомнить и правильно использовать общий интерфейс.

Полиморфизм включения

Этот полиморфизм называют чистым полиморфизмом. Применяя такую форму полиморфизма, родственные объекты можно использовать обобщенно. С помощью замещения и полиморфизма включения можно написать один метод для работы со всеми типами объектов TPerson. Используя полиморфизм включения и замещения можно работать с любым объектом, который проходит тест «is-A». Полиморфизм включения упрощает работу по добавлению к программе новых подтипов, так как не нужно добавлять конкретный метод для каждого нового типа, можно использовать уже существующий, только изменив в нем поведение системы. С помощью полиморфизма можно повторно использовать базовый класс; использовать любого потомка или методы, которые использует базовый класс.

Параметрический полиморфизм

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

Параметрические методы. Если полиморфизм включения влияет на наше восприятие объекта, то параметрические полиморфизм влияет на используемые методы, так как можно создавать методы родственных классов, откладывая объявление типов до времени выполнения. Для избежания написания отдельного метода каждого типа применяется параметрический полиморфизм, при этом тип параметров будет являться таким же параметром, как и операнды.

Параметрические типы. Вместо того, чтобы писать класс для каждого конкретного типа следует создать типы, которые будут реализованы во время выполнения программы то есть мы создаем параметрический тип. Полиморфизм переопределения. Абстрактные методы часто относятся к отложенным методам. Класс, в котором определен этот метод может вызвать метод и полиморфизм обеспечивает вызов подходящей версии отложенного метода в дочерних классах. Специальный полиморфизм допускает специальную реализацию для данных каждого типа. Полиморфизм-перегрузка - это частный случай полиморфизма. С помощью перегрузки одно и то же имя может обозначать различные методы, причем методы могут различаться количеством и типом параметров, то есть не зависят от своих аргументов. Метод может не ограничиваться специфическими типами параметров многих различных типов.

  1. Специальные функции члены класса: конструкторы, деструкторы, конструкторы копирования. Привести примеры кода на одном из объектно-ориентированных языков C++,JavaилиC#.

В классах и структурах есть члены, представляющие их данные и поведение. Члены класса включают все члены, объявленные в этом классе, а также все члены (кроме конструкторов и деструкторов), объявленные во всех классах в иерархии наследования данного класса. Закрытые члены в базовых классах наследуются, но недоступны из производных классов.

Далее перечислены виды членов, которые могут содержаться в классе или в структуре.

Поля

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

Поле - это переменная любого типа, которая объявлена непосредственно в классе или структуре.

Поля являются членами содержащих их типов.

Класс или структура могут иметь поля экземпляра или статические поля, либо поля обоих типов. Поля экземпляра определяются экземпляром типа. Если имеется класс T и поле экземпляра F, можно создать два объекта типа T и изменить значение поля F в каждом объекте, не изменяя значение в другом объекте. В противоположность этому, статическое поле относится к самому классу, и является общим для всех экземпляров этого класса. Изменения, выполненные из экземпляра А, будут немедленно видны экземплярам В и С, если они обращаются к полю.

Как правило, используются поля только для переменных, имеющих доступность private или protected. Данные, которые класс открывает для клиентского кода, должны предоставляться через методы, свойства и индексаторы. методами, свойствами и индексаторами Используя эти конструкции для косвенного доступа к внутренним полям, можно защититься от недопустимых входных значений. Закрытое поле, которое хранит данные, представленные открытым свойством, называется резервным хранилищем или резервным полем.

Поля обычно хранят данные, которые должны быть доступными нескольким методам класса и должны храниться дольше, чем время существования любого отдельного метода. Например, в классе, представляющем календарную дату, может быть три целочисленных поля: одно для месяца, одно для числа, одно для года. Переменные, не используемые вне области одного метода, должны быть объявлены как локальные переменные внутри тела самого метода.

Поля объявляются в блоке класса путем указания уровня доступа поля, за которым следует тип поля и имя поля. Например:

C#

public class CalendarEntry

{

// private field

private DateTime date;

// public field (Generally not recommended.)

public string day;

// Public property exposes date field safely.

public DateTime Date

{

get

{

return date;

}

set

{

// Set some reasonable boundaries for likely birth dates.

if (value.Year > 1900 && value.Year <= DateTime.Today.Year)

{

date = value;

}

else

throw new ArgumentOutOfRangeException();

}

}

// Public method also exposes date field safely.

// Example call: birthday.SetDate("1975, 6, 30");

public void SetDate(string dateString)

{

DateTime dt = Convert.ToDateTime(dateString);

// Set some reasonable boundaries for likely birth dates.

if (dt.Year > 1900 && dt.Year <= DateTime.Today.Year)

{

date = dt;

}

else

throw new ArgumentOutOfRangeException();

}

public TimeSpan GetTimeSpan(string dateString)

{

DateTime dt = Convert.ToDateTime(dateString);

if (dt != null && dt.Ticks < date.Ticks)

{

return date - dt;

}

else

throw new ArgumentOutOfRangeException();

}

}

Для доступа к члену объекта нужно добавить точку после имени объекта и указать имя поля: objectname.fieldname. Например:

C#

CalendarEntry birthday = new CalendarEntry();

birthday.day = "Saturday";

Полю можно назначить первоначальное значение, используя оператор присвоения при объявлении поля. Например, чтобы автоматически присвоить полю day значение "Monday", можно объявить поле day как указано в следующем примере:

C#

public class CalendarDateWithInitialization

{

public string day = "Monday";

//...

}

Поля инициализируются непосредственно перед вызовом конструктора для экземпляра объекта. Если конструктор присваивает полю значение, оно заменит значения, присвоенные при объявлении поля. Дополнительные сведения см. в разделе Использование конструкторов (Руководство по программированию на C#). Примечание

Инициализатор поля не может ссылаться на другие поля экземпляров.

Поля могут быть отмечены модификаторами public, private, protected, internal или protected internal. Эти модификаторы доступа определяют порядок доступа к полю для пользователей класса.

Методы

Методы определяют действия, которые может выполнить класс. Методы могут получать параметры, предоставляющие входные данные, и возвращать выходные данные посредством параметров. Также методы могут возвращать значения напрямую, без использования параметров.

Метод представляет собой блок кода, содержащий набор инструкций. Программа инициирует выполнение операторов, вызывая метод и задавая необходимые аргументы метода. В C# все инструкции выполняются в контексте метода. Метод Main является точкой входа для каждого приложения C#, и вызывается он средой CLR при запуске программы. Примечание

В этом разделе описываются именованные методы. Дополнительные сведения об анонимных функциях см. в разделе Анонимные функции (Руководство по программированию на C#).

Сигнатуры метода

Методы объявляются в классе или в структуре путем указания уровня доступа, например public или private, необязательных модификаторов, например abstract или sealed, возвращаемого значения, имени метода и списка параметров этого метода. Все вместе эти элементы образуют сигнатуру метода. Примечание

Тип возвращаемого методом значения не является частью сигнатуры метода с точки зрения перегрузки методов. В то же время он являются частью сигнатуры метода при определении совместимости между делегатом и методом, на который он указывает.

Параметры заключаются в круглые скобки и разделяются запятыми. Пустые скобки указывают на то, что у метода нет параметров. Следующий класс содержит три метода.

C#

abstract class Motorcycle

{

// Anyone can call this.

public void StartEngine() {/* Method statements here */ }

// Only derived classes can call this.

protected void AddGas(int gallons) { /* Method statements here */ }

// Derived classes can override the base class implementation.

public virtual int Drive(int miles, int speed) { /* Method statements here */ return 1; }

// Derived classes must implement this.

public abstract double GetTopSpeed();

}

Доступ к методам

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

C#

class TestMotorcycle : Motorcycle

{

public override double GetTopSpeed()

{

return 108.4;

}

static void Main()

{

TestMotorcycle moto = new TestMotorcycle();

moto.StartEngine();

moto.AddGas(15);

moto.Drive(5, 20);

double speed = moto.GetTopSpeed();

Console.WriteLine("My top speed is {0}", speed);

}

}

Параметры методов ДЛЯ. аргументов

Определение метода задает имена и типы любых необходимых параметров. Когда код вызова вызывает метод, он предоставляет конкретные значения, называемые аргументами, для каждого параметра. Аргументы должны быть совместимыми с типом параметра, но имя аргумента (если таковое имеется), используемое в коде вызова, не обязательно должно совпадать с именем параметра, определенного в методе. Например:

C#

public void Caller()

{

int numA = 4;

// Call with an int variable.

int productA = Square(numA);

int numB = 32;

// Call with another int variable.

int productB = Square(numB);

// Call with an integer literal.

int productC = Square(12);

// Call with an expression that evaulates to int.

productC = Square(productA * 3);

}

int Square(int i)

{

// Store input argument in a local variable.

int input = i;

return input * input;

}

Передача по ссылке И. передача по значению

По умолчанию при передаче методу типа значения передается копия объекта, а не сам объект. Поэтому изменения в аргументе не оказывают влияния на исходную копию в вызывающем методе. Тип значения по ссылке можно передать с помощью ключевого слова ref. Дополнительные сведения см. в разделе Передача параметров типа значения (Руководство по программированию в C#). Полный список встроенных типов значений см. в разделе Таблица типов значений (Справочник по C#).

Когда объект ссылочного типа передается методу, ссылка на этот объект передается. То есть метод возвращает не сам объект но аргумент, который показывает расположения объекта. При изменении членом объекта с помощью этой ссылки, то автоматически устанавливатьо изменение в аргументе в вызывающем методе, даже если передается объект значением.

Создании ссылочный тип с помощью ключевого слова class, как показано в следующем примере.

C#

public class SampleRefType

{

public int value;

}

Теперь, при передаче объекта, который основан на данном типе методу передается ссылка на объект. В следующем примере передает объект типа SampleRefType методу ModifyObject.

C#

public static void TestRefType()

{

SampleRefType rt = new SampleRefType();

rt.value = 44;

ModifyObject(rt);

Console.WriteLine(rt.value);

}

static void ModifyObject(SampleRefType obj)

{

obj.value = 33;

}

Примере выполняются по сути то же самое, что и предыдущий пример, в котором он передает аргумент по значению к методу. Но, поскольку ссылочный тип используется результат отличается. Изменение, выполненное в ModifyObject к полю value параметра, obj, также изменяется поле value аргумента, rt в методе TestRefType. Метод TestRefType отображает 33 как output.

Дополнительные сведения о том, как передавать ссылочные типы по ссылке и значением см. в разделе Передача параметров ссылочного типа (Руководство по программированию в C#) и Ссылочные типы (Справочник по C#).

Возвращаемые значения

Методы могут возвращать значения вызывающим их объектам. Если тип возвращаемого значения, указываемый перед именем метода, не равен void, для возвращения значения используется ключевое слово return. В результате выполнения инструкции с ключевым словом return, после которого указано значение нужного типа, вызвавшему метод объекту будет возвращено это значение. Кроме того, ключевое слово return останавливает выполнение метода. Если тип возвращаемого значения void, инструкцию return без значения все равно можно использовать для завершения выполнения метода. Если ключевое слово return отсутствует, выполнение метода завершится, когда будет достигнут конец его блока кода. Для возврата значений методами с типом возвращаемого значения отличным от void необходимо обязательно использовать ключевое слово return. Например, в следующих двух методах ключевое слово return служит для возврата целочисленных значений.

C#

class SimpleMath

{

public int AddTwoNumbers(int number1, int number2)

{

return number1 + number2;

}

public int SquareANumber(int number)

{

return number * number;

}

}

Чтобы использовать возвращаемое методом значение в вызываемом методе, вызов метода можно поместить в любое место кода, где требуется значение соответствующего типа. Кроме того, возвращаемое значение можно присвоить переменной. Например, следующие два примера кода выполняют одну и ту же задачу.

C#

int result = obj.AddTwoNumbers(1, 2);

result = obj.SquareANumber(result);

// The result is 9.

Console.WriteLine(result);

C#

result = obj.SquareANumber(obj.AddTwoNumbers(1, 2));

// The result is 9.

Console.WriteLine(result);

Использование локальной переменной в этом случае result, хранение значение является необязательным. Эта переменная может упростить читаемость кода либо быть необходимой, если необходимо сохранить исходное значение аргумента для целой области метода.

Соседние файлы в папке GEK