9.4.5. Ссылка на текущий объект
Рассмотрим простой пример использования класса Date
.
class Date {
// ...
int month() { return m; }
// ...
private:
int y, m, d; // год, месяц, день
};
void f(Date d1, Date d2)
{
cout << d1.month() << ' ' << d2.month() << '\n';
}
Откуда функции Date::month()
известно, что при первом вызове следует вернуть значение переменной d1.m
, а при втором — d2.m
? Посмотрите на функцию Date::month()
еще раз; ее объявление не имеет аргумента! Как функция Date::month()
“узнает”, для какого объекта она вызывается? Функции-члены класса, такие как Date::month()
, имеют неявный аргумент, позволяющий идентифицировать объект, для которого они вызываются. Итак, при первом вызове переменная m правильно ссылается на d1.m
, а при втором — на d2.m
. Другие варианты использования неявного аргумента описаны в разделе 17.10.
9.4.6. Сообщения об ошибках
Date
. Если мы создали правильные объекты класса Date
и все функции-члены написаны правильно, то мы никогда не получим объект класса Date
с неверным значением. Итак, следует предотвратить создание неправильных объектов класса Date
.
// простой класс Date (предотвращаем неверные даты)
class Date {
public:
class Invalid { }; // используется как исключение
Date(int y, int m, int d); // проверка и инициализация даты
// ...
private:
int y, m, d; // год, месяц, день
bool check(); // если дата правильная, возвращает true
};
Мы поместили проверку корректности даты в отдельную функцию check()
, потому что с логической точки зрения эта проверка отличается от инициализации, а также потому, что нам может потребоваться несколько конструкторов. Легко видеть, что закрытыми могут быть не только данные, но и функции.
Date::Date(int yy, int mm, int dd)
:y(yy), m(mm), d(dd) // инициализация данных - членов класса
{
if (!check()) throw Invalid(); // проверка корректности
}
bool Date::check() // возвращает true, если дата корректна
{
if (m<1 || 12
// ...
}
Имея это определение класса Date
, можно написать следующий код:
void f(int x, int y)
try {
Date dxy(2009,x,y);
cout << dxy << '\n'; // объявление оператора << см. в разделе 9.8
dxy.add_day(2);
}
catch(Date::Invalid) {
error("invalid date"); // функция error() определена
// в разделе 5.6.3
}
Теперь мы знаем, что оператор <<
и функция add_day()
всегда будут работать с корректными объектами класса Date
. До завершения разработки класса Date
, описанной в разделе 9.7, опишем некоторые свойства языка, которые потребуются нам для того, чтобы сделать это хорошо: перечисления и перегрузку операторов.
9.5. Перечисления
enum
(enumeration) — это очень простой тип, определенный пользователем, который задает множество значений (элементов перечисления) как символические константы. Рассмотрим пример.
enum Month {
jan=1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec
};