Урок 19. Наследование и конструкторы C#


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

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

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

Конструкторы и наследование

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

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

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

class Program
{
    static void Main()
    {
        MySubclass test = new MySubclass();
    }
}
 
 
class MyBaseClass
{
    public MyBaseClass()
    {
        Console.WriteLine("MyBaseClass constructor called.");
    }
}
 
 
class MySubclass : MyBaseClass
{
    public MySubclass()
    {
        Console.WriteLine("MySubclass constructor called.");
    }
}
 
/* 
 
MyBaseClass constructor called.
MySubclass constructor called.
 
*/
Это поведение повторяется для сложных иерархий наследуемых классов. Там, где существует более двух уровней наследования, сначала вызывается конструктор наименее специализированного класса, причем каждый конструктор по очереди вызывается вниз по дереву до тех пор, пока конструктор специально созданного класса не будет окончательно выполнен.

Финализаторы и наследование

Финализаторы или деструкторы, подобны конструкторам в сценариях наследования, поскольку они тоже не наследуются. Однако, поскольку финализатор не может быть вызван напрямую, это не является недостатком.

Когда объект находится вне области видимости и удаляется из памяти, его финализатор вызывается автоматически. Если объект основан на подклассе, деструктор суперкласса также будет вызван. Это происходит в обратном порядке к конструкторам. Сначала вызывается подкласс' finalizer, а затем базовый класс' finalizer.

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

~MyBaseClass()
{
    Console.WriteLine("MyBaseClass destructor called.");
}
Теперь добавьте аналогичный финализатор в файл " MySubclass:

~MySubclass()
{
    Console.WriteLine("MySubclass destructor called.");
}
Наконец, выполните программу. Обратите внимание на порядок отображения сообщений:

MyBaseClass constructor called.
MySubclass constructor called.
MySubclass destructor called.
MyBaseClass destructor called.
Вызов конкретных базовых конструкторов

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

Один базовый конструктор всегда вызывается при создании нового объекта. Однако выбор базового конструктора для выполнения может быть изменен с помощью ключевого слова base. Ключевое слово base используется аналогично ключевому слову "this"в перегрузке конструктора. Объявление конструктора объявляется как обычно, затем добавляется двоеточие (:). После двоеточия предоставляется ключевое слово base и список параметров базового конструктора для вызова. Каждый параметр, указанный в вызове базового класса, должен соответствовать одному из параметров в новом конструкторе или быть литеральным значением.

public Constructor(parameters-1) : base(parameters-2)
{
}
Чтобы продемонстрировать выполнение базовых конструкторов, добавьте новый конструктор в "MyBaseClass". Этот конструктор будет принимать один целочисленный параметр, который будет выведен на консоль.

public MyBaseClass(int aNumber)
{
    string output;
    output = string.Format("MyBaseClass created with value {0}.", aNumber);
    Console.WriteLine(output);
}
Теперь мы можем добавить конструктор в "MySubclass", который вызывает новый конструктор базового класса при создании экземпляра объекта:

public MySubclass(int startValue) : base(startValue)
{
    string output;
    output = string.Format("MySubclass created with value {0}.", startValue);
    Console.WriteLine(output);
}
Для проверки примера необходимо обновить метод Main в классе программы. В новой версии, объект "MySubclass" создается с помощью нового конструктора.

static void Main()
{
    MySubclass test = new MySubclass(10);
}
 
/* 
 
MyBaseClass created with value 10.
MySubclass created with value 10.
MySubclass destructor called.
MyBaseClass destructor called.
 
*/
Использование защищенных конструкторов

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

Чтобы показать использование защищенных конструкторов, измените конструктор MyBaseClass без параметров, чтобы сделать его защищенным:

protected MyBaseClass()
{
    Console.WriteLine("MyBaseClass constructor called.");
}
Если вы измените метод Main следующим образом, вы увидите, что конструктор по умолчанию больше не доступен для общего использования и код не будет компилироваться.

static void Main()
{
    MyBaseClass test = new MyBaseClass();
}
Защищенный конструктор по-прежнему доступен для подкласса. Мы можем продемонстрировать это, снова изменив основной метод. Попробуйте выполнить следующий код.

static void Main()
{
    MySubclass test = new MySubclass();
}
 
/* 
 
MyBaseClass constructor called.
MySubclass constructor called.
MySubclass destructor called.
MyBaseClass destructor called.
 
*/
Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.

тегистатьи IT, си шарп, ООП




Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.




Урок 7. Простая отправка email в Laravel через smtp
Урок 3. Работа с базой данных в Yii2
Работа с ini на C#