Использование конструкторов (Руководство по программированию на C#)
При создании экземпляра класса или структуры вызывается его конструктор. Конструкторы имеют имя, совпадающее с именем класса или структуры, и обычно инициализируют члены данных нового объекта.
В следующем примере класс с именем Taxi определяется с помощью простого конструктора. Затем оператор new создает экземпляр этого класса. Конструктор Taxi вызывается оператором new сразу после того, как новому объекту будет выделена память.
public class Taxi < public bool IsInitialized; public Taxi() < IsInitialized = true; >> class TestTaxi < static void Main() < Taxi t = new Taxi(); Console.WriteLine(t.IsInitialized); >>
Конструктор, который не принимает никаких параметров, называется конструктором без параметров. Конструкторы без параметров вызываются всякий раз, когда создается экземпляр объекта с помощью оператора new , а аргументы в new не передаются. В C# 12 представлены основные конструкторы. Основной конструктор задает параметры, которые необходимо предоставить для инициализации нового объекта. Дополнительные сведения см. в разделе Конструкторы экземпляров.
Если класс не является статическим, компилятор C# выделяет классам без конструкторов открытый конструктор без параметров, позволяющий создавать экземпляры классов. Дополнительные сведения см. в статье Статические классы и члены статических классов.
Создание экземпляров класса можно запретить, сделав конструктор закрытым, следующим образом:
class NLog < // Private Constructor: private NLog() < >public static double e = Math.E; //2.71828. >
Дополнительные сведения см. в разделе Закрытые конструкторы.
Конструкторы для типов структур похожи на конструкторы классов. При создании экземпляра new типа структуры вызывается конструктор. struct Если задано значение, default среда выполнения инициализирует всю память в структуре до 0. До C# 10 не может содержать явный конструктор без параметров, structs так как он предоставляется компилятором автоматически. Дополнительные сведения см. в разделе инициализации структуры и значенийпо умолчанию статьи «Типы структур».
В следующем коде используется конструктор Int32без параметров, чтобы убедиться, что целое число инициализировано:
int i = new int(); Console.WriteLine(i);
Однако следующий код вызывает ошибку компилятора, так как она не используется new , и потому что пытается использовать объект, который не был инициализирован:
int i; Console.WriteLine(i);
Кроме того, объекты на основе structs (включая все встроенные числовые типы) можно инициализировать или назначить, а затем использовать, как в следующем примере:
int a = 44; // Initialize the value type. int b; b = 33; // Or assign it before using it. Console.WriteLine(", ", a, b);
Классы и структуры могут определять конструкторы, которые принимают параметры, включая первичные конструкторы. Конструкторы, принимающие параметры, необходимо вызывать с помощью оператора new или base. Классы и структуры также могут определять несколько конструкторов, и для определения конструктора без параметров не требуется. Например:
public class Employee < public int Salary; public Employee() < >public Employee(int annualSalary) < Salary = annualSalary; >public Employee(int weeklySalary, int numberOfWeeks) < Salary = weeklySalary * numberOfWeeks; >>
Этот класс можно создать, воспользовавшись одним из следующих операторов:
Employee e1 = new Employee(30000); Employee e2 = new Employee(500, 52);
Конструктор может использовать ключевое слово base для вызова конструктора базового класса. Например:
public class Manager : Employee < public Manager(int annualSalary) : base(annualSalary) < //Add further instructions here. >>
В этом примере конструктор базового класса вызывается перед выполнением соответствующего ему блока. Ключевое слово base можно использовать как с параметрами, так и без них. Любые параметры для конструктора можно использовать как параметры для base или как часть выражения. Для получения дополнительной информации см. базу.
В производном классе, если конструктор базового класса не вызывается явным образом с помощью base ключевое слово, конструктор без параметров, если есть один, вызывается неявно. Следующие объявления конструктора фактически одинаковы:
public Manager(int initialData) < //Add further instructions here. >
public Manager(int initialData) : base() < //Add further instructions here. >
Если базовый класс не предлагает конструктор без параметров, производный класс должен выполнить явный вызов базового конструктора с помощью base .
Конструктор может вызывать другой конструктор в том же объекте с помощью ключевого слова this. Как и base , this можно использовать с параметрами или без, а все параметры в конструкторе доступны как параметры this или как часть выражения. Например, второй конструктор в предыдущем примере можно переписать, используя this :
public Employee(int weeklySalary, int numberOfWeeks) : this(weeklySalary * numberOfWeeks)
Применение ключевого слова this в приведенном выше примере привело к вызову конструктора:
public Employee(int annualSalary)
Конструкторы могут иметь пометку public, private, protected, internal, protected internal или private protected. Эти модификаторы доступа определяют, каким образом пользователи класса смогут создавать класс. Дополнительные сведения см. в статье Модификаторы доступа.
Конструктор можно объявить статическим, используя ключевое слово static. Статические конструкторы вызываются автоматически, непосредственно перед доступом к любым статическим полям и используются для инициализации элементов статического класса. Дополнительные сведения см. в разделе Статические конструкторы.
Спецификация языка C#
Дополнительные сведения см. в разделах Конструкторы экземпляров и Статические конструкторы в Спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.
См. также
- Система типов C#
- Конструкторы
- Методы завершения
Совместная работа с нами на GitHub
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
Как вызвать конструктор c
Конструкторы представляют специальную функцию, которая имеет то же имя, что и класс, которая не возвращает никакого значения и которая позволяют инициалилизировать объект класса во время го создания и таким образом гарантировать, что поля класса будут иметь определенные значения. При каждом создании нового объекта класса вызывается конструктор класса.
В прошлой теме был разработан следующий класс:
#include class Person < public: std::string name; unsigned age; void print() < std::cout >; int main() < Person person; // вызов конструктора person.name = "Tom"; person.age = 22; person.print(); >
Здесь при создании объекта класса Person, который называется person
Person person;
вызывается конструктор по умолчанию . Если мы не определяем в классе явным образом конструктор, как в случае выше, то компилятор автоматически компилирует конструктор по умолчанию. Подобный конструктор не принимает никаких параметров и по сути ничего не делает.
Теперь определим свой конструктор. Например, в примере выше мы устанавливаем значения для полей класса Person. Но, допустим, мы хотим, чтобы при создании объекта эти поля уже имели некоторые значения по умолчанию. Для этой цели определим конструктор:
#include class Person < public: std::string name; unsigned age; void print() < std::cout Person(std::string p_name, unsigned p_age) < name = p_name; age = p_age; std::cout >; int main() < Person tom("Tom", 38); // создаем объект - вызываем конструктор tom.print(); >
Теперь в классе Person определен конструктор:
Person(std::string p_name, unsigned p_age)
По сути конструктор представляет функцию, которая может принимать параметры и которая должна называться по имени класса. В данном случае конструктор принимает два параметра и передает их значения полям name и age, а затем выводит сообщение о создании объекта.
Если мы определяем свой конструктор, то компилятор больше не создает конструктор по умолчанию. И при создании объекта нам надо обязательно вызвать определенный нами конструктор.
Вызов конструктора получает значения для параметров и возвращает объект класса:
Person tom("Tom", 38);
После этого вызова у объекта person для поля name будет определено значение «Tom», а для поля age — значение 38. Вполедствии мы также сможем обращаться к этим полям и переустанавливать их значения.
В качестве альтернативы для создания объекта можно использовать инициализатор в фигурных скобках:
Person tom;
Тажке можно присвоить объекту результат вызова конструктора:
Person tom = Person("Tom", 38);
По сути она будет эквивалетна предыдущей.
Консольный вывод определенной выше программы:
Person has been created Name: Tom Age: 38
Конструкторы облегчают нам создание нескольких объектов, которые должны иметь разные значения:
#include class Person < public: std::string name; unsigned age; void print() < std::cout Person(std::string p_name, unsigned p_age) < name = p_name; age = p_age; std::cout >; int main() < Person tom; Person bob; Person sam; tom.print(); bob.print(); sam.print(); >
Здесь создаем три разных объекта класса Person (условно трех разных людей), и соответственно в данном случае консольный вывод будет следующим:
Person has been created Person has been created Person has been created Name: Tom Age: 38 Name: Bob Age: 42 Name: Sam Age: 25
Определение нескольких конструкторов
Подобным образом мы можем определить несколько конструкторов и затем их использовать:
#include class Person < std::string name<>; unsigned age<>; public: void print() < std::cout Person(std::string p_name, unsigned p_age) < name = p_name; age = p_age; >Person(std::string p_name) < name = p_name; age = 18; >Person() < name = "Undefined"; age = 18; >>; int main() < Person tom; // вызываем конструктор Person(std::string p_name, unsigned p_age) Person bob; // вызываем конструктор Person(std::string p_name) Person sam; // вызываем конструктор Person() tom.print(); bob.print(); sam.print(); >
В классе Person определено три конструктора, и в функции все эти конструкторы используются для создания объектов:
Name: Tom Age: 38 Name: Bob Age: 18 Name: Undefined Age: 18
Хотя пример выше прекрасно работает, однако мы можем заметить, что все три конструктора выполняют фактически одни и те же действия — устанавливают значения переменных name и age. И в C++ можем сократить их определения, вызова из одного конструктора другой и тем самым уменьшить объем кода:
#include class Person < std::string name<>; unsigned age<>; public: void print() < std::cout Person(std::string p_name, unsigned p_age) < name = p_name; age = p_age; std::cout Person(std::string p_name): Person(p_name, 18) // вызов первого конструктора < std::cout Person(): Person(std::string("Undefined")) // вызов второго конструктора < std::cout >; int main() < Person sam; // вызываем конструктор Person() sam.print(); >
Запись Person(string p_name): Person(p_name, 18) представляет вызов конструктора, которому передается значение параметра p_name и число 18. То есть второй конструктор делегирует действия по инициализации переменных первому конструктору. При этом второй конструктор может дополнительно определять какие-то свои действия.
Таким образом, следующее создание объекта
Person sam;
будет использовать третий конструктор, который в свою очередь вызывает второй конструктор, а тот обращается к первому конструктору.
Данная техника еще называется делегированием конструктора , поскольку мы делегируем инициализацию другому конструктору.
Параметры по умолчанию
Как и другие функции, конструкторы могут иметь параметры по умолчанию:
#include class Person < std::string name; unsigned age; public: // передаем значения по умолчанию Person(std::string p_name = "Undefined", unsigned p_age = 18) < name = p_name; age = p_age; >void print() < std::cout >; int main() < Person tom; Person bob; Person sam; tom.print(); // Name: Tom Age: 38 bob.print(); // Name: Bob Age: 18 sam.print(); // Name: Undefined Age: 18 >
Инициализация констант и списки инициализации
В теле конструктора мы можем передать значения переменным класса. Однако константы требуют особого отношения. Например, вначале определим следующий класс:
class Person < const std::string name; unsigned age<>; public: void print() < std::cout Person(std::string p_name, unsigned p_age) < name = p_name; age = p_age; >>;
Этот класс не будет компилироваться из-за отсутствия инициализации константы name. Хотя ее значение устанавливается в конструкторе, но к моменту, когда инструкции из тела конструктора начнут выполняться, константы уже должны быть инициализированы. И для этого необходимо использовать списки инициализации :
#include class Person < const std::string name; unsigned age<>; public: void print() < std::cout Person(std::string p_name, unsigned p_age) : name < age = p_age; >>; int main() < Person tom; tom.print(); // Name: Tom Age: 38 >
Списки инициализации представляют перечисления инициализаторов для каждой из переменных и констант через двоеточие после списка параметров конструктора:
Person(std::string p_name, unsigned p_age) : name
Здесь выражение name позволяет инициализировать константу значением параметра p_name. Здесь значение помещается в фигурные скобки, но также можно использовать кргулые:
Person(std::string p_name, unsigned p_age) : name(p_name)
Списки инициализации пободным образом можно использовать и для присвоения значений переменным:
class Person < const std::string name; unsigned age; public: void print() < std::cout Person(std::string p_name, unsigned p_age) : name(p_name), age(p_age) < >>;
При использовании списков инициализации важно учитывать, что передача значений должна идти в том порядке, в котором константы и переменные определены в классе. То есть в данном случае в классе сначала определена константа name, а потом переменная age. Соответственно в таком же порядке идет передача им значений. Поэтому при добавлении дополнительных полей или изменения порядка существующих придется следить, чтобы все инициализировалось в належащем порядке.
- Глава 1. Введение в С++
- Язык программирования С++
- Первая программа на Windows. Компилятор g++
- Первая программа на Windows. Компилятор Clang
- Первая программа на Windows. Компилятор Microsoft Visual C++
- Первая программа на Linux. Компилятор g++
- Первая программа на MacOS. Компилятор Clang
- Настройка параметров компиляции
- Локализация и кириллица в консоли
- Структура программы
- Переменные
- Типы данных
- Константы
- Ввод и вывод в консоли
- using. Подключение пространств имен и определение псевдонимов
- Арифметические операции
- Статическая типизация и преобразования типов
- Поразрядные операции
- Операции присваивания
- Условные выражения
- Конструкция if-else и тернарный оператор
- Конструкция switch-case
- Циклы
- Ссылки
- Массивы
- Многомерные массивы
- Массивы символов
- Введение в строки
- Что такое указатели
- Операции с указателями
- Арифметика указателей
- Константы и указатели
- Указатели и массивы
- Определение и объявление функций
- Область видимости объектов
- Параметры функции
- Передача аргументов по значению и по ссылке
- Константные параметры
- Оператор return и возвращение результата
- Указатели в параметрах функции
- Массивы в параметрах функции
- Параметры функции main
- Возвращение указателей и ссылок
- Перегрузка функций
- Рекурсивные функции
- Рекурсия на примере быстрой сортировки
- Указатели на функции
- Указатели на функции как параметры
- Тип функции
- Указатель на функцию как возвращаемое значение
- Разделение программы на файлы
- Внешние объекты
- Динамические объекты
- Динамические массивы
- unique_ptr
- shared_ptr
- Определение классов
- Конструкторы и инициализация объектов
- Управление доступом. Инкапсуляция
- Объявление и определение функций класса
- Конструктор копирования
- Константные объекты и функции
- Ключевое слово this
- Дружественные функции и классы
- Статические члены класса
- Деструктор
- Структуры
- Перечисления
- Наследование
- Управление доступом в базовых и производных классах
- Скрытие функционала базового класса
- Множественное наследование
- Виртуальные функции и их переопределение
- Преобразование типов
- Динамическое преобразование
- Особенности динамического связывания
- Чистые виртуальные функции и абстрактные классы
- Перегрузка операторов
- Операторы преобразования типов
- Оператор индексирования
- Переопределение оператора присваивания
- Пространства имен
- Вложенные классы
- Обработка исключений
- Вложенные try-catch
- Создание своих типов исключений
- Тип exception
- Типы исключений
- Шаблоны функций
- Шаблон класса
- Специализация шаблона класса
- Наследование и шаблоны классов
- Типы контейнеров
- Вектор
- Итераторы
- Операции с векторами
- Array
- List
- Forward_list
- Deque
- Стек std::stack
- Очередь std::queue
- Очередь приоритетов std::priority_queue
- Множества
- Словарь std::map
- Span
- Определение строк
- Строки с поддержкой Unicode
- Преобразование типов и строки
- Сравнение строк
- Получение подстроки и проверка начала и конца строки
- Поиск подстроки
- Изменение строки
- Операции с символами
- Программа подсчета слов
- Тип std:string_view
- rvalue
- Конструктор перемещения
- Оператор присваивания с перемещением
- Роль noexcept при перемещении
- Объекты функций
- Лямбда-выражения
- Захват внешних значений в лямбда-выражениях
- Шаблон std::function<>
- Минимальный и максимальный элементы
- Поиск элементов
- Копирование элементов
- Удаление элементов и идиома Remove-Erase Idiom
- Сортировка
- Представления. Фильтрация
- Проекция данных
- Пропуск элементов. drop_view и drop_while_view
- Извлечение диапазона элементов. take_view и take_while_view
- Цепочки представлений
- Оператор requires
- Концепты
- Выражение requires
- Ограничения типа для auto
- Базовые типы для работы с потоками
- Файловые потоки. Открытие и закрытие
- Чтение и запись текстовых файлов
- Переопределение операторов ввода и вывода
- Математические константы и операции
- Форматирование строк и функция format
- std::optional
- Управление ресурсами. Идиома RAII
- Идиома копирования и замены
- Идиома Move-and-Swap
- Первая программа в Visual Studio
- Первая программа в Qt Creator
Как вызвать конструктор с параметром, для класса являющегося членом другого класса.
Есть два класса c1 и c2 У каждого класса конструктор с параметром. Класс c1 является членом класса c2.
class c1< int v; public: c1(int n);// конструктор класса c1 >; c1::c1(int n) < v=n; printf("Constructior c1.\n"); >class c2< int v; public: c2(int n); // конструктор класса c2 c1 e1; >; c2::c2(int n) < v=n; e1.c1(n); //пытаюсь вызвать конструктор класса c1, но не выходит printf("Constructior c2\n"); >int main(int argc,char **argv)
При компиляции выдается сообщение о ошибке
test.cpp: In constructor ‘c2::c2(int)’: test.cpp:29: error: no matching function for call to ‘c1::c1()’ test.cpp:17: note: candidates are: c1::c1(int) test.cpp:12: note: c1::c1(const c1&) test.cpp:31: error: invalid use of ‘class c1’
Я так понимаю, что ошибка из за того, что конструктор вложенного класса имеет параметр. Вопрос. Как передать параметр конструктору члена класса?
Mixaluch384
04.11.11 23:08:48 MSK
Последнее исправление: Mixaluch384 04.11.11 23:10:51 MSK (всего исправлений: 1)Как из одного конструктора вызвать другой конструктор в C++?
При этом одновременно с вызовом другого конструктора нельзя вызывать конструкторы членов класса, например:
struct B < B() : x(1) <>B(int x_) : B(), x(x_) <> // ОШИБКА: нельзя одновременно вызвать B() и x() int x; >;
Как только был вызван один из конструкторов, объект считается полностью сконструированным, по этому исключение из вызывающего конструктора приведет к вызову деструктора класса:
struct C < C(const char*) < throw 1; >C() <> C(int) : C() < throw 1; >~C() < std::cout >; int main() < try < C c(""); // ничего не будет напечатано, деструктор не будет вызван >catch (. ) <> try < C c(1); // будет напечатано "~C" >catch (. ) <> >