Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Наследование в Си-шарп. Конструктор базового класса




В этом уроке мы рассмотрим с вами один из базовых принципов объектно-ориентированного программирования – наследование.

Начнем рассмотрение наследования из жизненных ситуаций. Для примера, возьмем такие понятия, как человек и студент. У любого человека есть имя, рост, вес и другие общие характеристики. Студент же является частным случаем человека, у него также есть имя, рост, вес, но кроме этого, он учится в некотором ВУЗе, на определенной специальности и имеет средний балл. С точки зрения наследования, в этом случае, студент является наследником понятия человек. Еще один пример можно привести с животными. Животное - это общее понятие. Животных можно поделить на рыб, птиц и млекопитающих. Каждый из этих групп животных различаются некоторым характеристиками, но у всех них есть общие особенности животных.

А теперь перейдем к программированию

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

Объявление нового класса, который будет наследовать другой класс, выглядит так:

class [имя_класса]: [имя_базового_класса]
{
// тело класса
}


Приведу простой пример использования наследования. На основе базового класса Животное создаются два класса Собака и Кошка, в эти два класса переходит свойство Имя животного:

class Animal
{
public string Name { get; set; }
}
class Dog: Animal
{
public void Guard()
{
// собака охраняет
}
}
class Cat: Animal
{
public void CatchMouse()
{
// кошка ловит мышь
}
}
class Program
{
static void Main(string[] args)
{
Dog dog1 = new Dog();
dog1.Name = "Барбос"; // называем пса
Cat cat1 = new Cat();
cat1.Name = "Барсик"; // называем кота
dog1.Guard(); // отправляем пса охранять
cat1.CatchMouse(); // отправляем кота на охоту
}
}


Вызов конструктора базового класса в Си-шарп

В базовом классе и классе-наследнике могут быть объявлены конструкторы, и тут возникает вопрос – какой конструктор за что должен отвечать, и как их вызывать. Логично будет сказать то, что конструктор базового класса будет создавать ту часть объекта, которая принадлежит базовому классу (ведь из базового класса о наследнике ничего неизвестно), а конструктор из наследника будет создавать свою часть.

Когда конструктор определен только в наследнике, то здесь всё просто – при создании объекта сначала вызывается конструктор по умолчанию базового класса, а затем конструктор наследника.

Когда конструкторы объявлены и в базовом классе, и в наследнике – нам необходимо вызывать их оба. Для вызова конструктора базового класса используется ключевое слово base. Объявление конструктора класса-наследника с вызовом базового конструктора имеет следующую структуру:

[имя_конструктора_класса-наследника] ([аргументы]): base ([аргументы])
{
// тело конструктора
}


В базовый конструктор передаются все необходимые аргументы для создания базовой части объекта.

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

class Animal
{
public string Name { get; set; }

public Animal(string name)
{
Name = name;
}
}
class Parrot: Animal
{
public double BeakLength { get; set; } // длина клюва

public Parrot(string name, double beak): base(name)
{
BeakLength = beak;
}
}
class Dog: Animal
{
public Dog(string name): base (name)
{
// здесь может быть логика создания объекта Собака
}
}
class Program
{
static void Main(string[] args)
{
Parrot parrot1 = new Parrot("Кеша", 4.2);
Dog dog1 = new Dog("Барбос");
}
}


Доступ к членам базового класса из класса-наследника

Здесь стоит отметить, что в классе-наследнике мы можем получить доступ к членам базового класса которые объявлены как public, protected, internal и protected internal. Члены базового класса с модификатором доступа private также переходят в класс-наследник, но к ним могут иметь доступ только члены базового класса. Например, свойство, объявленное в базовом классе, которое управляет доступом к закрытому полю, будет работать корректно в классе-наследнике, но отдельно получить доступ к этому полю из класса-наследника мы не сможем.

Домашнее задание

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

Массив указателей на базовый класс в Си-шарп. Операторы is и as

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

В Си-шарп есть возможность создания массива (или списка) указателей на базовый класс в котором в качестве элементов могут быть объекты класса-наследника. Например, мы можем создать массив объектов Животное, и элементами такого массива будут объекты классов Собака, Кошка. Пример:

class Animal
{
public string Name { get; set; }

public Animal(string name)
{
Name = name;
}
}
class Dog: Animal
{
public Dog(string name): base(name)
{ }

public void Guard()
{
// собака охраняет
}
}
class Cat: Animal
{
public Cat(string name): base(name)
{ }

public void CatchMouse()
{
// кошка ловит мышь
}
}

class Program
{
static void Main(string[] args)
{
List<Animal> animals = new List<Animal>(); // создаем список указателей на базовый класс
animals.Add(new Dog("Барбос"));
animals.Add(new Cat("Барсик"));
animals.Add(new Dog("Палкан"));

foreach (Animal animal in animals)
{
Console.WriteLine(animal.Name);
}
Console.ReadLine();
}
}

 

Хотя как элементы в этот список мы добавляли объекты классов-наследников Собака и Кошка, будучи элементами списка указателей на базовый класс, эти объекты преобразовываются к объектам базового класса, и мы имеем доступ только к той части объектов, которая описана в базовом классе – мы не можем здесь вызвать методы Guard() или CatchMouse(), но при этом имеем доступ к имени животного.

Обратное здесь невозможно. Нельзя создать массив объектов класса Собака, и записать в него объекты класса Животное.

Оператор is

Оператор is работает очень просто – он проверяет совместимость объекта с указанным типом (принадлежит ли объект определенному классу). Оператор is возвращает истину (true), если объект принадлежит классу. Истинна будет также при проверке совместимости объекта класса-наследника и базового класса:

static void Main(string[] args)
{
Dog dog1 = new Dog("Барбос");

Console.WriteLine(dog1 is Dog); // true
Console.WriteLine(dog1 is Animal); // true
Console.WriteLine(dog1 is Cat); // false
Console.ReadLine();
}

 

Пользуясь оператором is и явным преобразованием, теперь мы можем полноценно использовать массив указателей на базовый класс:

class Animal
{
public string Name { get; set; }

public Animal(string name)
{
Name = name;
}
}
class Dog: Animal
{
public Dog(string name): base(name)
{ }

public void Guard()
{
Console.WriteLine(Name + " охраняет");
}
}
class Cat: Animal
{
public Cat(string name): base(name)
{ }

public void CatchMouse()
{
Console.WriteLine(Name + " ловит мышь");
}
}

class Program
{
static void Main(string[] args)
{
List<Animal> animals = new List<Animal>();
animals.Add(new Dog("Барбос"));
animals.Add(new Cat("Барсик"));
animals.Add(new Dog("Палкан"));

foreach (Animal animal in animals)
{
if (animal is Dog) // проверяем является ли данное животное собакой
((Dog)animal).Guard();
else ((Cat)animal).CatchMouse();
}
Console.ReadLine();
}
}


Здесь, использовав явное преобразование, мы получаем полный доступ к объектам из списка, и можем вызывать методы Guard() и CatchMouse().

Оператор as

В примере выше, вместо явного приведения типов можно было использовать оператор as. (Dog)animal эквивалентно выражению animal as Dog. Разница между оператором as и явным приведением лишь в том, что в случае невозможности преобразования, оператор as возвращает null, тогда как явное приведение выбрасывает исключение. Пример программы выше, только уже с оператором as:

class Program
{
static void Main(string[] args)
{
List<Animal> animals = new List<Animal>();
animals.Add(new Dog("Барбос"));
animals.Add(new Cat("Барсик"));
animals.Add(new Dog("Палкан"));

foreach (Animal animal in animals)
{
if (animal is Dog) // проверяем является ли данное животное собакой
(animal as Dog).Guard();
else (animal as Cat).CatchMouse();
}
Console.ReadLine();
}
}

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...