Что такое Конструктор в C++?
Конструктор – это специальная функция-член класса, которая автоматически вызывается при создании объекта этого класса. Конструкторы позволяют инициализировать члены класса и выполнять другие необходимые операции при создании объекта.
Конструктор по умолчанию:
class MyClass < public: // Конструктор по умолчанию MyClass() < // Инициализация переменных, если необходимо >>;
Параметризованный конструктор:
class Rectangle < public: // Параметризованный конструктор Rectangle(int w, int h) : width(w), height(h) < // Дополнительные операции при создании объекта >private: int width; int height; >;
Почему использовать конструкторы:
- Конструкторы обеспечивают инициализацию объектов и подготовку к их использованию.
- Они упрощают код, делают его более читаемым и предсказуемым.
Когда использовать конструкторы:
- При необходимости выполнения определенных действий при создании объекта.
- Для инициализации членов класса перед использованием объекта.
Использование конструкторов в C++ является важной частью объектно-ориентированного программирования и позволяет эффективно управлять жизненным циклом объектов.
Конструкторы (руководство по программированию на C#)
Всякий раз, когда создается экземпляр класса или структуры , его конструктор вызывается. Класс или структура может иметь несколько конструкторов, принимающих различные аргументы. Конструкторы позволяют программисту задавать значения по умолчанию, ограничивать число установок и писать код, который является гибким и удобным для чтения. Дополнительные сведения и примеры см. в разделах Конструкторы экземпляров и Использование конструкторов.
Существует несколько действий, которые являются частью инициализации нового экземпляра. Эти действия выполняются в следующем порядке:
- Для полей экземпляра задано значение 0. Обычно это делается средой выполнения.
- Запускаются инициализаторы полей. Инициализаторы полей в большинстве производных типов выполняются.
- Запускаются инициализаторы полей базового типа. Инициализаторы полей начинаются с прямой базы с каждым базовым типом System.Object.
- Запускаются конструкторы базовых экземпляров. Все конструкторы экземпляров, начиная с Object.Object каждого базового класса, до прямого базового класса.
- Выполняется конструктор экземпляра. Конструктор экземпляра для выполнения типа.
- Запускаются инициализаторы объектов. Если выражение включает в себя инициализаторы объектов, они выполняются после запуска конструктора экземпляра. Инициализаторы объектов выполняются в текстовом порядке.
Предыдущие действия выполняются при инициализации нового экземпляра. Если для нового экземпляра задано значение, default все поля экземпляра struct имеют значение 0.
Если статический конструктор не выполняется, статический конструктор выполняется до того, как будут выполняться какие-либо действия конструктора экземпляра.
Синтаксис конструктора
Конструктор — это метод, имя которого совпадает с именем его типа. Его сигнатура метода включает только дополнительный модификатор доступа, имя метода и его список параметров; он не включает возвращаемый тип. В приведенном ниже примере демонстрируется конструктор для класса с именем Person .
public class Person < private string last; private string first; public Person(string lastName, string firstName) < last = lastName; first = firstName; >// Remaining implementation of Person class. >
Если конструктор поддерживает реализацию в виде оператора, можно использовать определение тела выражения. В следующем примере определяется класс Location , конструктор которого имеет один строковый параметр name. Определение тела выражения присваивает аргумент полю locationName .
public class Location < private string locationName; public Location(string name) =>Name = name; public string Name < get =>locationName; set => locationName = value; > >
Статические конструкторы
В приведенных выше примерах показаны конструкторы экземпляров, которые создают новый объект. В классе или структуре также может быть статический конструктор, который инициализирует статические члены типа. Статические конструкторы не имеют параметров. Если вы не предоставили статический конструктор для инициализации статических полей, компилятор C# инициализирует статические поля значениями по умолчанию, как показано в статье Значения по умолчанию типов C#.
В следующем примере статический конструктор используется для инициализации статического поля.
public class Adult : Person < private static int minimumAge; public Adult(string lastName, string firstName) : base(lastName, firstName) < >static Adult() < minimumAge = 18; >// Remaining implementation of Adult class. >
Можно также определить статический конструктор с помощью определения тела выражения, как показано в следующем примере.
public class Child : Person < private static int maximumAge; public Child(string lastName, string firstName) : base(lastName, firstName) < >static Child() => maximumAge = 18; // Remaining implementation of Child class. >
Дополнительные сведения и примеры см. в разделе Статические конструкторы.
В этом разделе
- Использование конструкторов
- Конструкторы экземпляров
- Частные конструкторы
- Статические конструкторы
- Практическое руководство. Создание конструктора копий
См. также
- Руководство по программированию на C#
- Система типов C#
- Методы завершения
- static
- Why Do Initializers Run In The Opposite Order As Constructors? Part One (Почему инициализаторы выполняются в порядке, обратном действию конструкторов? Часть 1)
Совместная работа с нами на GitHub
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
Обратная связь
Coming soon: Throughout 2024 we will be phasing out GitHub Issues as the feedback mechanism for content and replacing it with a new feedback system. For more information see: https://aka.ms/ContentUserFeedback.
Отправить и просмотреть отзыв по
Дополнительные ресурсы
Значок отказа согласно Закону Калифорнии о защите конфиденциальности потребителей (CCPA)
- Светлая
- Темная
- Высокая контрастность
- Предыдущие версии
- Блог
- Участие в доработке
- Конфиденциальность
- Условия использования
- Товарные знаки
- © Microsoft 2024
Что такое параметризированный конструктор с
В прошлой статье для создания объекта использовался конструктор по умолчанию. Однако мы сами можем определить свои конструкторы. Как правило, конструктор выполняет инициализацию объекта. При этом если в классе определяются свои конструкторы, то он лишается конструктора по умолчанию.
На уровне кода конструктор представляет метод, который называется по имени класса, который может иметь параметры, но для него не надо определять возвращаемый тип. Например, определим в классе Person простейший конструктор:
Person tom = new Person(); // Создание объекта класса Person tom.Print(); // Имя: Tom Возраст: 37 class Person < public string name; public int age; public Person() < Console.WriteLine("Создание объекта Person"); name = "Tom"; age = 37; >public void Print() < Console.WriteLine($"Имя: Возраст: "); > >
Итак, здесь определен конструктор, который выводит на консоль некоторое сообщение и инициализирует поля класса.
public Person()
Конструкторы могут иметь модификаторы, которые указываются перед именем конструктора. Так, в данном случае, чтобы конструктор был доступен вне класса Person, он определен с модификатором public .
Определив конструктор, мы можем вызвать его для создания объекта Person:
Person tom = new Person(); // Создание объекта Person
В данном случае выражение Person() как раз представляет вызов определенного в классе конструктора (это больше не автоматический конструктор по умолчанию, которого у класса теперь нет). Соответственно при его выполнении на консоли будет выводиться строка «Создание объекта Person»
Подобным образом мы можем определять и другие конструкторы в классе. Например, изменим класс Person следующим образом:
Person tom = new Person(); // вызов 1-ого конструктора без параметров Person bob = new Person("Bob"); //вызов 2-ого конструктора с одним параметром Person sam = new Person("Sam", 25); // вызов 3-его конструктора с двумя параметрами tom.Print(); // Имя: Неизвестно Возраст: 18 bob.Print(); // Имя: Bob Возраст: 18 sam.Print(); // Имя: Sam Возраст: 25 class Person < public string name; public int age; public Person() < name = "Неизвестно"; age = 18; >// 1 конструктор public Person(string n) < name = n; age = 18; >// 2 конструктор public Person(string n, int a) < name = n; age = a; >// 3 конструктор public void Print() < Console.WriteLine($"Имя: Возраст: "); > >
Теперь в классе определено три конструктора, каждый из которых принимает различное количество параметров и устанавливает значения полей класса. И мы можем вызвать один из этих конструкторов для создания объекта класса.
Консольный вывод данной программы:
Имя: Неизвестно Возраст: 18 Имя: Bob Возраст: 18 Имя: Sam Возраст: 25
Стоит отметить, что начиная с версии C# 9 мы можем сократить вызов конструктора, убрав из него название типа:
Person tom = new (); // аналогично new Person(); Person bob = new ("Bob"); // аналогично new Person("Bob"); Person sam = new ("Sam", 25); // аналогично new Person("Sam", 25);
Ключевое слово this
Ключевое слово this представляет ссылку на текущий экземпляр/объект класса. В каких ситуациях оно нам может пригодиться?
Person sam = new("Sam", 25); sam.Print(); // Имя: Sam Возраст: 25 class Person < public string name; public int age; public Person() < name = "Неизвестно"; age = 18; >public Person(string name) < this.name = name; age = 18; >public Person(string name, int age) < this.name = name; this.age = age; >public void Print() => Console.WriteLine($"Имя: Возраст: "); >
В примере выше во втором и третьем конструкторе параметры называются также, как и поля класса. И чтобы разграничить параметры и поля класса, к полям класса обращение идет через ключевое слово this . Так, в выражении
this.name = name;
первая часть — this.name означает, что name — это поле текущего класса, а не название параметра name. Если бы у нас параметры и поля назывались по-разному, то использовать слово this было бы необязательно. Также через ключевое слово this можно обращаться к любому полю или методу.
Цепочка вызова конструкторов
В примере выше определены три конструктора. Все три конструктора выполняют однотипные действия — устанавливают значения полей name и age. Но этих повторяющихся действий могло быть больше. И мы можем не дублировать функциональность конструкторов, а просто обращаться из одного конструктора к другому также через ключевое слово this , передавая нужные значения для параметров:
class Person < public string name; public int age; public Person() : this("Неизвестно") // первый конструктор < >public Person(string name) : this(name, 18) // второй конструктор < >public Person(string name, int age) // третий конструктор < this.name = name; this.age = age; >public void Print() => Console.WriteLine($"Имя: Возраст: "); >
В данном случае первый конструктор вызывает второй, а второй конструктор вызывает третий. По количеству и типу параметров компилятор узнает, какой именно конструктор вызывается. Например, во втором конструкторе:
public Person(string name) : this(name, 18)
идет обращение к третьему конструктору, которому передаются два значения. Причем в начале будет выполняться именно третий конструктор, и только потом код второго конструктора.
Стоит отметить, что в примере выше фактически все конструкторы не определяют каких-то других действий, кроме как передают третьему конструктору некоторые значения. Поэтому в реальности в данном случае проще оставить один конструктор, определив для его параметров значения по умолчанию:
Person tom = new(); Person bob = new("Bob"); Person sam = new("Sam", 25); tom.Print(); // Имя: Неизвестно Возраст: 18 bob.Print(); // Имя: Bob Возраст: 18 sam.Print(); // Имя: Sam Возраст: 25 class Person < public string name; public int age; public Person(string name = "Неизвестно", int age = 18) < this.name = name; this.age = age; >public void Print() => Console.WriteLine($"Имя: Возраст: "); >
И если при вызове конструктора мы не передаем значение для какого-то параметра, то применяется значение по умолчанию.
Первичные конструкторы
Начиная с версии C# 12 в язык C# была добавлена поддержка первичных конструкторов (Primary constructors). Первичные конструкторы позволяют добавлять параметры к определению класса и использовать эти параметры внутри класса:
var tom = new Person("Tom", 38); Console.WriteLine(tom); public class Person(string name, int age) < public Person(string name) : this(name, 18) < >public void Print() => Console.WriteLine($"name: , age: "); >
Здесь для класса Person определен первичный конструктор с двумя параметрами — name и age. Эти параметры применяются для используются в методе Print.
За кадром для каждого параметра первичного конструктора в классе создается приватное поле, которое хранит значение параметра. Благодаря этому они могут использоваться в теле класса.
Кроме первичных конструкторов класс может определять дополнительные конструкторы, как примере выше. Но эти дополнительные конструкторы должны вызывать первичный конструктор:
public Person(string name) : this(name, 18)
Инициализаторы объектов
Для инициализации объектов классов можно применять инициализаторы . Инициализаторы представляют передачу в фигурных скобках значений доступным полям и свойствам объекта:
Person tom = new Person < name = "Tom", age = 31 >; // или так // Person tom = new() < name = "Tom", age = 31 >; tom.Print(); // Имя: Tom Возраст: 31
С помощью инициализатора объектов можно присваивать значения всем доступным полям и свойствам объекта в момент создания. При использовании инициализаторов следует учитывать следующие моменты:
- С помощью инициализатора мы можем установить значения только доступных из вне класса полей и свойств объекта. Например, в примере выше поля name и age имеют модификатор доступа public, поэтому они доступны из любой части программы.
- Инициализатор выполняется после конструктора, поэтому если и в конструкторе, и в инициализаторе устанавливаются значения одних и тех же полей и свойств, то значения, устанавливаемые в конструкторе, заменяются значениями из инициализатора.
Инициализаторы удобно применять, когда поле или свойство класса представляет другой класс:
Person tom = new Person < name = "Tom", company = < title = "Microsoft">>; tom.Print(); // Имя: Tom Компания: Microsoft class Person < public string name; public Company company; public Person() < name = "Undefined"; company = new Company(); >public void Print() => Console.WriteLine($»Имя: Компания: «); > class Company
Обратите внимание, как устанавливается поле company :
company =
Деконструкторы
Деконструкторы (не путать с деструкторами) позволяют выполнить декомпозицию объекта на отдельные части.
Например, пусть у нас есть следующий класс Person:
class Person < string name; int age; public Person(string name, int age) < this.name = name; this.age = age; >public void Deconstruct(out string personName, out int personAge) < personName = name; personAge = age; >>
В этом случае мы могли бы выполнить декомпозицию объекта Person так:
Person person = new Person("Tom", 33); (string name, int age) = person; Console.WriteLine(name); // Tom Console.WriteLine(age); // 33
Значения переменным из деконструктора передаюся по позиции. То есть первое возвращаемое значение в виде параметра personName передается первой переменной — name, второе возващаемое значение — переменной age.
По сути деконструкторы это не более,чем более удобный способ разложения объекта на компоненты. Это все равно, что если бы мы написали:
Person person = new Person("Tom", 33); string name; int age; person.Deconstruct(out name, out age);
При получении значений из деконструктора нам необходимо предоставить столько переменных, сколько деконструктор возвращает значений. Однако бывает, что не все эти значения нужны. И вместо возвращаемых значений мы можм использовать прочерк _ . Например, нам надо получить только возраст пользователя:
Person person = new Person("Tom", 33); (_, int age) = person; Console.WriteLine(age); // 33
Поскольку первое возвращаемое значение — это имя пользователя, которое не нужно, в в данном случае вместо переменной прочерк.
Параметризированные конструкторы
Конструкторам можно передавать аргументы. Обычно эти аргументы используются для того, чтобы помочь инициализировать создаваемый объект. Для того, чтобы создать параметризированный конструктор, достаточно попросту добавить параметры, как это делается для любой другой функции. При определении тела конструктора, т.е. кода, который реализует конструктор, эти параметры используются для инициализации объекта. Например, можно усовершенствовать класс queue путем передачи ему в качестве аргумента числа, служащего идентификатором объекта. Объявление класса queue будет иметь следующий вид:
// создание класса очередь
class queue int q[100];
int sloс, rloc;
int who; // содержит идентификатор очереди
public:
queue(int id); // параметризированный конструктор
~queue (); // деструктор
void qput(int i);
int qget();
>
Переменная who используется для хранения значения идентификатора, служащего для идентификации объекта типа queue. Его значение определяется аргументом id при создании объекта. Конструктор queue() будет выглядеть следующим образом:
Для передачи аргумента конструктору необходимо задать его значение при объявлении объекта. С++ поддерживает два способа решения этой задачи. Первый из них выглядит следующим образом:
queue а = queue(101);
Здесь конструктор класса queue вызывается непосредственно с передачей ему значения 101. Значением переменной а служит сам созданный объект.
Второй способ короче и более непосредственно ведет к цели. В этом методе аргумент или аргументы следуют непосредственно за именем объекта в скобках. Следующая строка кода служит той же самой цели, что и предыдущее объявление объекта:
Поскольку этот метод используется почти всеми программистами, пишущими на языке С++, то он и будет использоваться.
Общая форма для передачи аргументов конструктору имеет следующий вид:
Здесь список_аргументов представляет собой список аргументов, разделенных запятыми. Эти аргументы и передаются конструктору.
Следующая версия программы queue демонстрирует передачу аргументов конструктору:
#include
// создание класса очередь
class queue int q[100];
int sloс, rloc;
int who; // содержит идентификатор очереди
public:
queue (int id); // параметризированный конструктор
~queue(); // деструктор
void qput(int i);
int qget();
> ;
/ / конструктор
queue::queue(int id)
sloс = rloc = 0;
who = id;
cout >
/ / деструктор
queue::~queue()
cout >
void queue::qput(int i)
if (sloс == 99) cout return;
>
sloc++;
q[sloc] = i;
>
int queue::qget()
if (rloc == sloс) cout return 0;
>
rloc++;
return q[rloc];
>
int main()
queue a(1), b(2); // создание двух объектов типа queue
a.qput(10);
b.qput(19);
a.qput(20);
b.qput(1);
cout cout cout cout return 0;
>
Эта программа выводит следующий текст:
Queue 1 initialized.
Queue 2 initialized.
10 20 19 1
Queue 2 destroyed.
Queue 1 destroyed.
Посмотрев на функцию main(), мы увидим, что объект а имеет в качестве идентификатора 1, а объект b — 2.
Хотя в данном примере при создании объекта ему передается только один аргумент, можно передавать также и несколько аргументов. Например, в следующей программе объектам типа widget передаются два значения:
#include
class widget int i;
int j;
public:
widget (int a, int b);
void put_widget();
>;
widget::widget (int a, int b)
i = a;
j = b;
>
void widget::put__widget ()
cout >
int main()
widget x(10, 20),
y(0, 0);
x.put_widget();
у.put_widget();
return 0;
>
Эта программа выведет на экран значения
10 20
0 0