Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ооп-экз.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
149.7 Кб
Скачать

9.Наследование. Функциональное назначение. Реализация. Примеры применения.

Насле́дование — механизм объектно-ориентированного программирования позволяющий описать новый класс на основе уже существующего (родительского), при этом свойства и функциональность родительского класса заимствуются новым классом. Другими словами, класс-наследник реализует спецификацию уже существующего класса (базовый класс). Это позволяет обращаться с объектами класса-наследника точно так же, как с объектами базового класса.

Наследование (Генерализация) — объекты дочернего класса наследуют все свойства родительского класса.

Пример:

publicclass A { }

publicinterface I1 { }

publicinterface I2 { }

publicclass B : A, I1, I2 { }

Агрегация — объекты одного класса входят в объекты другого.

Пример:

class A

{ public class B : A { } }

10.Наследование. Конструктор по умолчанию. Назначение.

Насле́дование— механизм объектно-ориентированного программирования

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

Другими словами, класс-наследник реализует спецификацию уже существующего класса (базовый класс). Это позволяет обращаться с объектами класса-наследника точно так же, как с объектами базового класса.

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

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

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

public Derived() {}

public Derived(string name, int cred, int deb):base (name, cred)

{ debet = deb; }

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

Итак, вызов конструктора - потомка приводит к цепочке вызовов конструкторов - предков, заканчивающейся вызовом конструктора прародителя. Затем в обратном порядке создаются объекты, начиная с объекта прародителя, и выполняются тела соответствующих конструкторов, инициализирующие поля и выполняющие другую работу этих конструкторов. Последним создается объект потомка и выполняется тело конструктора потомка.

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

Наследование (Генерализация) — объекты дочернего класса наследуют все свойства родительского класса.

Пример:

publicclass A { }

publicinterface I1 { }

publicinterface I2 { }

publicclass B : A, I1, I2 { }

Агрегация — объекты одного класса входят в объекты другого.

Пример:

class A

{ public class B : A { } }

11. Наследование. Проблема тождественности имен членов классов. Реализация. Примеры применения.

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

// Пример сокрытия имени в связи с наследованием.

using System;

class A { public int i = 0; }

// Создаем производный класс,

class В : А {

new int i; // Этот член i скрывает член i класса А.

public В(int b) {

i = b; // Член i в классе В.

public void show() {

Console.WriteLine(

"Член i в производном классе: " + i);

class NameHiding {

public s t a t i c void Main() {

В ob = new В(2);

ob.show();

Во-первых, обратите внимание на использование ключевого слова new при объявлении члена i в классе в. По сути, он сообщает компилятору о том, что вы знаете, что создается новая переменная с именем i, которая скрывает переменную i в базовом классе А. Если убрать слово new, компилятор сгенерирует предупреждающее сообщение.Результаты выполнения этой программы выглядят так: /

I Член i в производном классе: 2

Поскольку в классе в определяется собственная переменная экземпляра с именем

i , она скрывает переменную i, определенную в классе А. Следовательно, при вызове

метода show() для объекта типа в, отображается значение переменной для б, а не для а

Использование ключевого слова base для доступа к скрытому имени. Существует вторая форма использования ключевого слова base, которая действует подобно ссылке this, за исключением того, что ссылка base всегда указывает на базовый класс производного класса, в котором она используется. В этом случае формат ее записи такой: base.член Здесь в качестве элемента член можно указывать либо метод, либо переменную экземпляра. Эта форма ссылки base наиболее применима в тех случаях, когда имя члена в производном классе скрывает член с таким же именем в базовом классе. Рассмотрим следующую версию иерархии классов из предыдущего примера:

// Использование ссылки base для доступа к скрытому имени.

using System;

class A { public int i = 0; }

// Создаем производный класс,

class В : А { new int i; // Эта переменная i скрывает i класса А.

publicВ(int a, int b) { ! base.i = а; // Так можно обратиться к i класса А.

i = b; // Переменная i в классе В. }

public void show() {

// Эта инструкция отображает переменную i в классе А.

Console.WriteLine("i в базовом классе: " + base.i);

// Эта инструкция отображает переменную i в классе В.

Console.WriteLine("i в производном классе: " + i );

class UncoverName { public static void Main() {

В ob = new В(1f 2 );

ob.show();

Результаты выполнения этой программы выглядят так: i в базовом классе: 1

i в производном классе: 2 Несмотря на то что переменная экземпляра i в классе В скрывает переменную, base позволяет получить доступ к базовому классу.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]