Читаем Программирование полностью

  Очевидное правило гласит: не помещайте тела функций-членов в объявление класса, если вам не нужна повышенная эффективность программы за счет использования небольших подставляемых функций. Большие функции, скажем, состоящие из пяти и более строк, ничего не выиграют от подстановки. Не следует делать подставляемыми функции, содержащие более одного-двух выражений.

<p id="AutBody_Root163"><strong>9.4.5. Ссылка на текущий объект</strong></p>

Рассмотрим простой пример использования класса 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.

<p id="AutBody_Root164"><strong>9.4.6. Сообщения об ошибках</strong></p>

  Что делать при обнаружении некорректной даты? В каком месте кода происходит поиск некорректных дат? В разделе 5.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, опишем некоторые свойства языка, которые потребуются нам для того, чтобы сделать это хорошо: перечисления и перегрузку операторов. 

<p id="AutBody_Root165"><strong>9.5. Перечисления</strong></p>

  Перечисление enum (enumeration) — это очень простой тип, определенный пользователем, который задает множество значений (элементов перечисления) как символические константы. Рассмотрим пример.

enum Month {

  jan=1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec

};

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже