Страница 6 из 88
5.2.4 Инициализация Инициализация объектов класса с помощью таких функций как set_date() - неэлегантное и чреватое ошибками решение. Поскольку явно не было указано, что объект требует инициализации, программист может либо забыть это сделать, либо сделать дважды, что может привести к столь же катастрофическим последствиям. Лучше дать программисту возможность описать функцию, явно предназначенную для инициализации объектов. Поскольку такая функция конструирует значение данного типа, она называется конструктором. Эту функцию легко распознать - она имеет то же имя, что и ее класс:
class date { // ... date(int, int, int); };
Если в классе есть конструктор, все объекты этого класса будут проинициализированы. Если конструктору требуются параметры, их надо указывать:
date today = date(23,6,1983); date xmas(25,12,0); // краткая форма date my_birthday; // неправильно, нужен инициализатор
Часто бывает удобно указать несколько способов инициализации объекта. Для этого нужно описать несколько конструкторов:
class date { int month, day, year; public: // ... date(int, int, int); // день, месяц, год date(int, int); // день, месяц и текущий год date(int); // день и текущие год и месяц date(); // стандартное значение: текущая дата date(const char*); // дата в строковом представлении };
Параметры конструкторов подчиняются тем же правилам о типах параметров, что и все остальные функции ($$4.6.6). Пока конструкторы достаточно различаются по типам своих параметров, транслятор способен правильно выбрать конструктор:
date today(4); date july4("July 4, 1983"); date guy("5 Nov"); date now; // инициализация стандартным значением
Размножение конструкторов в примере c date типично. При разработке класса всегда есть соблазн добавить еще одну возможность, - а вдруг она кому-нибудь пригодится. Чтобы определить действительно нужные возможности, надо поразмышлять, но зато в результате, как правило, получается более компактная и понятная программа. Сократить число сходных функций можно с помощью стандартного значения параметра. В примере с date для каждого параметра можно задать стандартное значение, что означает: "взять значение из текущей даты".
class date { int month, day, year; public: // ... date(int d =0, int m =0, y=0); // ... };
date::date(int d, int m, int y) { day = d ? d : today.day; month = m ? m : today.month; year = y ? y : today.year; // проверка правильности даты // ... }
Когда используется стандартное значение параметра, оно должно отличаться от всех допустимых значений параметра. В случае месяца и дня очевидно, что при значении нуль - это так, но неочевидно, что нуль подходит для значения года. К счастью, в европейском календаре нет нулевого года, т.к. сразу после 1 г. до р.х. (year==-1) идет 1 г. р.х. (year==1). Однако для обычной программы это, возможно, слишком тонкий момент. Объект класса без конструктора может инициализироваться присваиванием ему другого объекта этого же класса. Это незапрещено и в том случае, когда конструкторы описаны:
date d = today; // инициализация присваиванием
На самом деле, имеется стандартный конструктор копирования, определенный как поэлементное копирование объектов одного класса. Если такой конструктор для класса X не нужен, можно переопределить его как конструктор копирования X::X(const X&). Подробнее поговорим об этом в $$7.6.
|