Конструкторы

Понятие «Конструктор» (constructor) неотделимо от понятия класса. Конструкторы — это специальные функции, вызываемые автоматически при инициализации объектов. Их имена совпадают с именами классов, которым они принадлежат, и они не имеют типа возврата. У одного класса может быть более одного конструктора, различающихся сигнатурами. Конструкторы полезны для инициализации полей класса. Интересно, что компилятор создает конструктор по умолчанию без параметров, он устанавливает поля в 0, false или null (для объектов).

Рассмотрим пример. Создадим класс «Треугольник» с тремя полями и одним методом, вычисляющим его периметр.

using System;
namespace Конструктор
{
   class Triangle
   {
      int a;
      int b;
      int c;
      public int perimeter()
      {
         return a + b + c;
      }
   }
   class Program
   {
      static void Main(string[] args)
      {
         Triangle tr = new Triangle(); // создаем объект         
         Console.WriteLine("периметр = " + tr.perimeter());
         Console.ReadKey();
      }
   }
}

Результат выполнения программы: периметр = 0

АНАЛИЗ

В окне ошибок первый раз появляются 3 предупреждения (но не ошибки!):
 Полю «Конструктор.Triangle.c» нигде не присваивается значение, поэтому оно всегда будет иметь значение по умолчанию 0 (тоже для полей a и b).

Так как сработал конструктор без параметров Triangle(), то всем сторонам треугольника был присвоен 0. Добавим в определение класса строку:  Triangle(); и запустим программу. Получим сообщение об ошибке:
Тип «Конструктор.Triangle» уже определяет член «Triangle» с такими же типами параметров.
Это подтверждает тот факт, что конструктор с нулем параметров уже был создан. Теперь добавим в описание класса конструктор с тремя параметрами:

public Triangle(int a, int b, int c)
{
   this.a = a;
   this.b = b;
   this.c = c;
}

А в метод Main() первую строку заменим на:

 Triangle tr = new Triangle(3,4,5);

Результат выполнения программы: периметр = 12

То есть, мы выполнили инициализацию полей   (a, b, c) объекта tr, на что указывает ключевое слово this в операторах конструктора. Иначе нам бы пришлось указывать разные имена: a = d; где d был бы тогда первым элементом в списке параметров.  Оператор типа a = a оставит значение поля a=0, а компилятор выдаст предупреждение:
Проведено присвоение той же переменной; действительно выполнить такое назначение, а не иное?

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

Напомним, что так как по умолчанию поля класса являются закрытыми (private), то их нельзя изменить непосредственно в программе, например:
tr.c = 7;
В этом случае получим сообщение об ошибке:
«Конструктор.Triangle.c» недоступен из-за его уровня защиты.

Ошибка устранится, если к описанию поля с добавим модификатор public:
public int c;
Однако это не является хорошим тоном в ООП, поле перестает быть защищенным.

В отличие от структур классы относятся к ссылочным (reference) типам данных, их экземпляры (объекты)  “живут” в куче (heap). Поэтому при создании объекта резервируется для полей место в куче, и в зависимости от конструктора полям задаются значения 0, false или null (для конструктора по умолчанию), либо соответствующие значения (для конструктора с параметрами).

Проверьте на практике правильность следующих утверждений:

1) Можно ли создать конструктор по умолчанию? — Да.
2) Если создается свой конструктор, будет ли компилятор генерировать конструктор по умолчанию? —  Нет.
3) Если в своём конструкторе не будут инициализированы некоторые поля, будут ли они автоматически инициализированы компилятором?  — Да.
4) Разрешается ли инициализировать переменные там, где их объявляют? — Да.

Пример конструктора при наследовании класса

Воспользуемся готовым классом Random из библиотеки System. Создадим дочерний класс RwName («Random with Name»), добавим в него поле s и два метода, а также модифицируем конструктор класса:

using System;
namespace Конструктор
{
   class RwName : Random
   {
      public string s;
      public RwName(string s)
      {
         this.s = s;
      }
      public double NextD()
      {
         return this.NextDouble();
      }
      public void Rezult()
      {
         Console.WriteLine(this.s + this.NextDouble());
      }
   }
   class Program
   {
      static void Main(string[] args)
      {  
         RwName r = new RwName("Вещественное число: ");
         Console.WriteLine(r.NextD());
         r.Rezult();
         Console.ReadKey();
      }
   }
}

Теперь объект класса получит наименование через конструктор, а два метода класса стали более специфичными. Даже если вы не указали в объявлении класса имя «родителя», он  все равно будет наследовать конструктор класса Object.

Статический конструктор

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

using System;
namespace Конструктор
{
   class StatClass
   {
      public static int q;
      public int p;
      // Статический конструктор
      static StatClass()
      {
         q = 33;
      }
      // Обычный конструктор
      public StatClass()
      {
         p = 44;
      }
   }
   class Program
   {
      static void Main(string[] args)
      {
         StatClass ob = new StatClass();
         Console.WriteLine("Доступ к полю p экземпляра: " + ob.p);
         Console.WriteLine("Доступ к полю q: " + StatClass.q);
         Console.ReadLine();
      }
   }
}

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

ВЫВОД

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

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Пролистать наверх