Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции по ая.docx
Скачиваний:
22
Добавлен:
20.09.2019
Размер:
276.66 Кб
Скачать

Наследование

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

Класс потомок наследует все возможности родительского класса – все поля и все методы. Поля и методы родительского класса, снабженные атрибутом private, являются закрытыми, и методы, создаваемые потомком, не могут к ним обращаться напрямую, а только через методы, наследованные от родителя. Хорошей стратегией при проектировании класса является использование модификатора доступа protected вместо модификатора private, разрешая потомкам класса прямой доступ ко всем полям и методам родительского класса. Потомок наследует не все. Он не наследует конструкторы родительского класса. Конструкторы потомок должен создавать сам.

Для наследования, при описании класса потомка после его имени необходимо поставить двоеточие и написать имя класса родителя. Например:

Класс родитель

class Man

{

}

Класс потомок

class Student : Man

{

}

Потомок может только добавить собственные поля и может скрыть поля родителя. Скрываемые поля следует снабжать модификатором new. Если этого не сделать, то родительское поле все равно будет скрыто, и на этапе компиляции будет выдано предупреждение о возникшей ситуации.

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

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

Потомок может создать новый собственный метод с именем, отличным от имен наследуемых методов. В этом случае никаких особенностей нет.

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

  • перегрузка метода. Она возникает, когда сигнатура создаваемого метода отличается от сигнатуры наследуемых методов предков. В этом случае в классе потомка будет несколько перегруженных методов с одним именем, и вызов нужного метода определяется обычными правилами перегрузки методов;

  • переопределение метода. Метод родителя в этом случае должен иметь модификатор virtual, abstract или override. При переопределении сохраняется сигнатура и модификаторы доступа наследуемого метода;

  • скрытие метода. Если родительский метод не является виртуальным или абстрактным, то потомок может создать новый метод с тем же именем и той же сигнатурой, скрыв родительский метод в данном контексте. Здесь ситуация такая же, как и со скрытием полей. При вызове метода по его имени предпочтение будет отдаваться методу потомка. Это не означает, что метод родителя становится недоступным. Скрытый родительский метод всегда может быть вызван, если при вызове уточнить имя метода родительским именем base.

Метод потомка, скрывающий метод родителя, следует сопровождать модификатором new, указывающим на новый метод. Если этот модификатор опущен, но из контекста ясно, что речь идет о новом методе, то выдается предупреждающее сообщение при компиляции проекта.

Рассмотрим пример. Создадим класс описывающий человека Man и класс потомок описывающий студента. При помощи атрибута protected закроем поля класса Man от клиентов класса, но откроем для потомков. Определим два конструктора для класса Man. Первый для инициализации объекта значениями по умолчанию, второй для инициализации объекта значениями передаваемыми клиентами. Создадим класс потомок Student с двумя полями. Определим в данном классе конструктор, принимающий 4 параметра, два для класса родителя два для класса потомка. При этом воспользуемся ключевым словом :base, для определения параметров передаваемых конструктору родителя. В приведённом примере конструктору родителя передаться два параметра указанные после ключевого слова base, а именно NewName, NewAge Переопределим метод Print родителя при помощи ключевого слова new в потомке.

class Man

{

protected string name;

protected int age;

public Man()

{

name = "";

age = 0;

}

public Man(string NewName, int NewAge)

{

name = NewName;

age = NewAge;

}

public void Print()

{

Console.WriteLine("{0} {1} лет", name, age);

}

}

class Student : Man

{

string gruoup;

int recordBook;

public Student(string NewName, int NewAge, string NewGruoup, int NewRecordBook):base( NewName, NewAge)

{

gruoup = NewGruoup;

recordBook = NewRecordBook;

}

new public void Print()

{

Console.WriteLine("{0} {1} лет, группа {2}, зачетка {3}", name, age, gruoup, recordBook);

}

}

class Program

{

static void Main()

{

Man m1 = new Man("Иванов", 18);

m1.Print();

Student s1 = new Student("Петров", 18, "БАС-21", 111);

s1.Print();

Console.ReadLine();

}

}