Когда создается объект типа Counter, нам хотелось бы, чтобы его поле count было инициализировано нулевым значением, поскольку большинство счетчиков начинают отсчет именно с нуля. Мы могли бы провести инициализацию с помощью вызова функции set_count() с аргументом, равным нулю, или создать специальный метод zero_count(), обнуляющий значение функции. Недостаток такого подхода заключается в том, что эти функции необходимо вызывать явно каждый раз при создании объекта типа Counter:
Counter cl: // при определении объекта
cl.zero_count(): // это необходимое действие
Подобные действия легко могут привести к неправильной работе всей программы, поскольку программисту для этого достаточно забыть проинициализировать хотя бы одну переменную после ее создания. Если в программе создается множество таких переменных, гораздо проще и надежнее было бы инициализировать их автоматически при создании. В нашем примере конструктор Counter() выполняет эти действия. Конструктор вызывается автоматически при создании каждого из объектов. Таким образом, в функции mainQ оператор
Counter cl. с2:
создает два объекта типа Counter. При создании каждого из них вызывается конструктор Counter(), присваивающий полю counter нулевое значение. Таким образом, кроме создания переменных, данный оператор еще присваивает их полям нулевое значение.
Инициализаторы в конструкторах
Главной задачей конструктора класса является инициализация данных создаваемых им объектов. Однако производить инициализацию данных при помощи оператора присваивания в теле конструктора не рекомендуется.
Инициализация осуществляется при помощи списка инициализации, расположенного между двоеточием, которое следует за закрывающей круглой скобкой в заголовке конструктора, и телом конструктора. Присваиваемые при инициализации данных значения записываются в круглых скобках после идентификаторов членов-данных и отделяются друг от друга запятыми.
Порядок следования идентификаторов в списке инициализации не имеет значения.
Для каждого объекта класса Counter конструктор выполняет инициализацию поля count нулем. Вы, вероятно, ожидали, что это действие будет произведено в теле конструктора приблизительно следующим образом:
count()
{ count =0; }
Такая форма записи не рекомендуется, несмотря на то, что она не содержит ошибок. Инициализация в нашем примере происходит следующим образом:
count(): count(0)
{ }
Инициализация расположена между прототипом метода и телом функции и предварена двоеточием. Инициализирующее значение помещено в скобках после имени поля.
Если необходимо инициализировать сразу несколько полей класса, то значения разделяются запятыми, и в результате образуется список инициализации:
someClass (): m1(7), m2(33), m2(4) { }
Результаты работы программы со счетчиком
В функции main() рассматриваемой нами программы создаются два объекта класса Counter с именами cl и с2. Затем на экран выводятся значения полей каждого из объектов, которые, согласно нашей задумке, должны быть инициализированы нулевыми значениями. Далее значение счетчика cl инкрементируется один раз, а значение счетчика с2 — два раза, и программа вновь заставляет объекты вывести значения своих полей на экран (что является в данном случае вполне корректным). Результат работы программы выглядит следующим образом:
cl=0
с2=0
cl=1
с2=2
Для того чтобы убедиться в том, что конструктор функционирует именно так, как мы описали выше, заставим его печатать сообщение во время выполнения:
counter(): count(0)
{ cout << "Конструктор\n": }
Теперь результат работы программы будет выглядеть следующим образом:
Конструктор
Конструктор
cl=0
с2=0
cl=1
с2=2
Как можно видеть, конструктор исполняется дважды: первый раз — для переменной cl, второй раз — для переменной с2, во время выполнения оператора
counter cl, с2; в функции main().
Конструктор по умолчанию
Конструктор по умолчанию — конструктор, не требующий параметров. Этот конструктор всегда должен быть определен для любого класса. Конструктор по умолчанию может не выполнять никаких действий, но чаще всего он инициализирует данные класса нулевыми значениями.
Объявление конструктора по умолчанию имеет следующий формат:
public:имя_класса ();
Например, для класса своок прототип конструктора по умолчанию записывается со спецификатором открытого доступа
public: CBook ();
Пример реализации конструктора по умолчанию ]
СВоок:: СВоок (): m_year (0), m_pTitle ("")
{ m_author [ 0 ] = ‘\0'; }
В результате работы этого конструктора будет построен объект-книга, у которого данное year получит нулевое значение, массив author начнется с нулевого байта точно так же, как и название книги, на которое указывает pTitie. Для инициализации автора не может быть использован инициализатор, так как этот член-данное объявлен в классе как символьный массив.
Конструктор с параметрами
Конструктор с параметрами инициализирует значения данных объекта значениями полученных параметров. Параметров будет столько, сколько данных необходимо проинициализировать. Прототип такого конструктора имеет формат:
public:имя_класса (список формальных параметров);
Для класса CBook конструктор с параметрами может иметь следующий прототип: CBook (char*, char*, int);
Пример реализации конструктора с параметрами
СВоок:: СВоок (char *author, char *title, int year)
: m_уеаг (year), m_pTitle (title)
{
strncpy_s (m_author, 50, author, 49);
if (strlen (author) > 49) m_author [ 49 ] = '\0';
}
В результате работы этого конструктора будет построен объект-книга, у которого данное щ_уеаг получит значение параметра year, в массив m_author будет скопировано не более 49 байтов из строки author, и указатель m_pTitie будет содержать адрес, по которому скопировано значение title.