// Year::Invalid
Стоило ли выполнять дополнительную работу и вводить обозначения для лет? Естественно, это зависит от того, какие задачи вы собираетесь решать с помощью типа Date, но в данном случае мы сомневаемся в этом и не хотели бы создавать отдельный класс Year
Обратите внимание на слова static const
min
и max
. Они позволяют нам определить символические константы для целых типов в классах. Использование модификатора static
по отношению к члену класса гарантирует, что в программе существует только одна копия его значения, а не по одной копии на каждый объект данного класса.9.7.2. Копирование
Мы всегда должны создавать объекты, иначе говоря, всегда предусматривать инициализацию и конструкторы. Вероятно, это самые важные члены класса: для того чтобы написать их, необходимо решить, как инициализировать объект и что значит корректность его значений (т.е. определить инвариант). Уже даже размышления об инициализации помогут вам избежать ошибок.
Затем необходимо решить, можно ли копировать объекты и как это делать? Для класса Date
Month
ответ очевиден: копирование необходимо, и его смысл тривиален: просто копируются все члены класса. Фактически это предусмотрено по умолчанию. Если не указано ничего другого, компьютер сделает именно это. Например, если перечисление Date
используется для инициализации или стоит в правой части оператора присваивания, то все его члены будут скопированы.Date holiday(1978, Date::jul, 4); // инициализация
Date d2 = holiday;
Date d3 = Date(1978, Date::jul, 4);
holiday = Date(1978, Date::dec, 24); // присваивание
d3 = holiday;
Обозначение Date(1978, Date::dec, 24)
cout << Date(1978, Date::dec, 24);
В данном случае конструктор класса действует почти как литерал. Это часто удобнее, чем сначала создавать переменную или константу, а затем использовать ее лишь один раз.
А если нас не устраивает копирование по умолчанию? В таком случае мы можем либо определить свое собственное копирование (см. раздел 18.2), либо создать конструктор копирования и закрытый оператор копирующего присваивания (см. раздел 14.2.4).
9.7.3. Конструкторы по умолчанию
Неинициализированные переменные могут быть источником серьезных ошибок. Для того чтобы решить эту проблему, в языке С++ предусмотрено понятие конструктора, гарантирующее, что каждый объект класса будет инициализирован. Например, мы объявили конструктор Date::Date(int,Month,int)
Date
будет правильно проинициализирован. В данном случае это значит, что программист должен предоставить три аргумента соответствующих типов. Рассмотрим пример.Date d1; // ошибка: нет инициализации
Date d2(1998); // ошибка: слишком мало аргументов
Date d3(1,2,3,4); // ошибка: слишком много аргументов
Date d4(1,"jan",2); // ошибка: неправильный тип аргумента
Date d5(1,Date::jan,2); // OK: используется конструктор с тремя
// аргументами
Date d6 = d5; // OK: используется копирующий конструктор
Обратите внимание на то, что, даже несмотря на то, что мы определили конструктор для класса Date
Date
. Многие классы имеют вполне разумные значения по умолчанию; иначе говоря, для них существует очевидный ответ на вопрос: какое значение следует использовать, если инициализация не выполнена? Рассмотрим пример.string s1; // значение по умолчанию: пустая строка ""
vector
vector