- •Классы, Объекты и Методы
- •Struct DateStruct {
- •Int month;
- •Int year;
- •Методы классов
- •Void print () {
- •Int main () {
- •Int main () {
- •Int main () {
- •Спецификаторы доступа public и private
- •Int year; // открыто по умолчанию
- •Int main () {
- •Int main () {
- •Int main ()
- •Структуры. Классы
- •Инкапсуляция, Геттеры и Сеттеры Инкапсуляция
- •Int m_array[10];
- •Int main () {
- •IntArray array;
- •Void setValue(int index, int value) {
- •Функции доступа (геттеры и сеттеры)
- •Int m_month;
- •Int m_year;
- •Int main () {
- •Краткий обзор l-value и r-value
- •Инициализация ссылок
- •Ссылки в качестве параметров в функциях
- •Void changeN (int &ref) {
- •Int main () {
- •Int value1;
- •Int otherValue;
- •Ссылки. Указатели
- •Конструкторы
- •Int main () {
- •Конструкторы по умолчанию
- •Конструкторы с параметрами
- •Int m_numerator;
- •Int m_denominator;
- •Int getNumerator () {return m_numerator; }
- •Int getDenominator () {return m_denominator; }
- •Копирующая инициализация
- •Уменьшение количества конструкторов
- •Неявно генерируемый конструктор по умолчанию
- •Int main () {
- •Int main () {
- •Классы, содержащие другие классы
- •Int main() {
- •Список инициализации членов класса
- •Списки инициализации членов класса
- •Int m_value1;
- •Values() {
- •Int m_value1;
- •Инициализация массивов в классе
- •Инициализация переменных-членов, которые являются классами
- •Int main() {
- •Использование списков инициализации
- •Int m_value1;
- •Int m_value1;
- •Int m_value1;
- •Порядок выполнения в списке инициализации
- •Инициализация нестатических членов класса
- •Void print() {
- •Int main() {
- •Void print() {
- •Int main() {
- •Void print() {
- •Int main() {
- •Void print() {
- •Int main() {
- •Делегирующие конструкторы
- •Void DoX() {
- •Init();
- •Init();
- •Void Init()
- •Int main() {
- •Ещё о делегирующих конструкторах
- •Деструкторы
- •Имена деструкторов
- •Пример использования деструктора на практике
- •Выполнение конструкторов и деструкторов
- •Int getId() { return m_nId; }
- •Int main() {
- •Предупреждение о функции exit()
- •Скрытый указатель this
- •Скрытый указатель *this
- •Int m_number;
- •Int getNumber() { return m_number; }
- •Int main() {
- •Указатель this всегда указывает на текущий объект. Явное указание указателя this
- •Int data;
- •Цепочки методов класса
- •Заключение
Конструкторы по умолчанию
Конструктор, который не имеет параметров (или содержит параметры, которые все имеют значения по умолчанию), называется конструктором по умолчанию.
Он вызывается, если пользователем не указаны значения для инициализации. Например:
#include <iostream>
class Fraction {
private:
int m_numerator;
int m_denominator;
public:
Fraction () // конструктор по умолчанию
{
m_numerator = 0;
m_denominator = 1;
}
int getNumerator () {return m_numerator;}
int getDenominator () {return m_denominator;}
double getValue () {return static_cast<double>(m_numerator) / m_denominator;}
};
int main () {
Fraction drob; // так как нет никаких аргументов, то вызывается
// конструктор по умолчанию Fraction ()
std::cout << drob.getNumerator() << "/" << drob.getDenominator() << '\n';
return 0;
}
Этот класс содержит дробь в виде отдельных значений типа int.
Конструктор по умолчанию называется Fraction (как и класс).
Поскольку мы создали объект класса Fraction без аргументов, то конструктор по умолчанию сработал сразу же после выделения памяти для объекта, и инициализировал наш объект.
Результат выполнения программы:
0/1
Обратите внимание, наш числитель (m_numerator) и знаменатель (m_denominator) были инициализированы значениями, которые мы задали в конструкторе по умолчанию!
Это настолько полезная особенность, что почти каждый класс имеет свой конструктор по умолчанию.
Без него значениями нашего числителя и знаменателя был бы мусор до тех пор, пока мы явно не присвоили бы им нормальные значения.
Конструкторы с параметрами
Хотя конструктор по умолчанию отлично подходит для обеспечения инициализации наших классов значениями по умолчанию, часто может быть нужно, чтобы экземпляры нашего класса имели определенные значения, которые могли бы быть разными для разных объектов.
Поэтому конструкторы также могут быть объявлены с параметрами.
Вот пример конструктора, который имеет два целочисленных параметра, которые используются для инициализации числителя и знаменателя:
#include <cassert>
class Fraction {
private:
Int m_numerator;
Int m_denominator;
public:
Fraction () { // конструктор по умолчанию
m_numerator = 0;
m_denominator = 1;
}
// Конструктор с двумя параметрами, один из которых имеет значение
//по умолчанию
Fraction (int numerator, int denominator=1) {
assert (denominator != 0);
m_numerator = numerator;
m_denominator = denominator;
}
Int getNumerator () {return m_numerator; }
Int getDenominator () {return m_denominator; }
double getValue () {return static_cast<double>(m_numerator) / m_denominator; }
};
В контексте программирования на C/C++ вызов функции assert() означает, что условие в параметре обязательно верно, и если это не так, то дальнейшее выполнение программы невозможно.
Таким образом, assert прервет нормальную работу программы (иногда с выводом сообщения), если условие, которое проверяет assert, равно false.
Обратите внимание, теперь у нас есть два конструктора: конструктор по умолчанию, который будет вызываться, если мы не предоставим значения, и конструктор с параметрами, который будет вызываться, если мы предоставим значения.
Эти два конструктора могут мирно сосуществовать в одном классе благодаря перегрузке функций.
Фактически, вы можете определить любое количество конструкторов до тех пор, пока у них будут уникальные параметры.
Как использовать конструктор с параметрами? Всё просто! Прямая инициализация:
int a (7); // прямая инициализация
Fraction drob (4, 5); // инициализируем напрямую, вызывается
// конструктор Fraction (int, int)
Здесь мы инициализировали нашу дробь числами 4 и 5, результат: 4/5.
В C++11 можно использовать uniform-инициализацию:
int a { 7 }; // uniform-инициализация
Fraction drob {4, 5}; // uniform-инициализация, вызывается конструктор
//Fraction (int, int)
Мы также можем указать только один параметр для конструктора с параметрами, а второе значение будет значением по умолчанию:
Fraction seven (7); // вызывается конструктор Fraction (int, int),
//второй параметр использует значение по умолчанию
Значения по умолчанию для конструкторов работают точно так же, как и для любой другой функции, поэтому в вышеприведенном примере, когда мы вызываем seven (7) , вызывается Fraction(int, int), второй параметр которого равен 1 (значение по умолчанию).
Правило: Используйте прямую инициализацию или uniform-инициализацию с объектами ваших классов.
