Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:

Ключевое слово

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

int Date::day const

{

++d; // ошибка: попытка изменить объект в константной

// функции - члене

return d;

}

Естественно, как правило, мы не собираемся мошенничать. В основном компилятор обеспечивает защиту от несчастных случаев, что очень полезно при разработке сложных программ.

9.7.5. Члены и вспомогательные функции

Разрабатывая минимальный (хотя и полный) интерфейс, мы вынуждены оставлять за бортом много полезных операций. Функцию, которая могла бы быть просто, элегантно и эффективно реализована как самостоятельная функция (т.е. не функция-член), следует реализовать за пределами класса. Таким образом, функция не сможет повредить данные, хранящиеся в объекте класса. Предотвращение доступа к данным является важным фактором, поскольку обычные методы поиска ошибок “вращаются вокруг типичных подозрительных мест”; иначе говоря, если с классом что-то не так, мы в первую очередь проверяем функции, имеющие прямой доступ к его представлению: одна из них обязательно является причиной ошибки. Если таких функций десяток, нам будет намного проще работать, чем если их будет пятьдесят.

Пятьдесят функций для класса

Date
! Возможно, вы думаете, что мы шутим. Вовсе нет: несколько лет назад я делал обзор нескольких коммерческих библиотек для работы с календарем и обнаружил в них множество функций вроде
next_Sunday
,
next_workday
и т.д. Пятьдесят — это совсем не невероятное число для класса, разработанного для удобства пользователей, а не для удобства его проектирования, реализации и сопровождения.

Отметим также, что если представление изменяется, то переписать достаточно только функции, которые имеют к ней прямой доступ. Это вторая важная практическая причина для минимизации интерфейса. Разрабатывая класс

Date
, мы могли решить, что дату лучше представлять в виде целого числа дней, прошедших с 1 января 1900 года, а не в виде тройки (год, месяц, день). В этом случае нам придется изменить только функции-члены.

Рассмотрим несколько примеров вспомогательных функций (helper functions).

Date next_Sunday(const Date& d)

{

// имеет доступ к объекту d, используя d.day, d.month

// и d.year

// создает и возвращает новый объект класса Date

}

Date next_weekday(const Date& d) { /* ... */ }

bool leapyear(int y) { /* ... */ }

bool operator==(const Date& a, const Date& b)

{

return a.year==b.year

&& a.month==b.month

&& a.day==b.day;

}

bool operator!=(const Date& a, const Date& b)

{

return !(a==b);

}

Вспомогательные функции также называют функциями-помощниками. Различие между этими и другими функциями, не являющимися членами класса, заключается в логике работы; иначе говоря, вспомогательная функция представляет собой концепцию проектирования, а не концепцию языка программирования. Вспомогательная функция часто получает в качестве аргументов объекты класса, для которого они играют вспомогательную роль. Хотя существуют исключения, например функция
leapyear
. Часто для идентификации вспомогательных функций используются пространства имен (см. раздел 8.7).

namespace Chrono {

class Date { /* ... */ };

bool is_date(int y, Date::Month m, int d); // true для

// корректных данных

Date next_Sunday(const Date& d) { /* ... */ }

Date next_weekday(const Date& d) { /* ... */ }

bool leapyear(int y) { /* ... */ } // см. пример 10

bool operator==(const Date& a, const Date& b) { /* ... */ }

// ...

}

Обратите внимание на функции

==
и
!=
. Это типичные вспомогательные функции. Для многих классов функции
==
и
!=
имеют очевидный смысл, но, поскольку это не распространяется на все классы, компилятор не может создать их вместо программиста, как копирующий конструктор или копирующее присваивание.

Отметьте также, что мы ввели вспомогательную функцию

is_date
, которая заменяет функцию
Date::check
, поскольку проверка корректности даты во многом не зависит от представления класса
Date
. Например, нам не нужно знать, как представлены объекты класса
Date
для того, чтобы узнать, что дата “30 января 2008 года” является корректной, а “30 февраля 2008 года” — нет. Возможно, существуют аспекты даты, которые зависят от ее представления (например, корректна ли дата “30 января 1066 года”), но (при необходимости) конструктор
Date
может позаботиться и об этом.

9.8. Класс Date

Итак, соединим все идеи и понятия вместе и посмотрим, как будет выглядеть класс

Date
. Там, где тело функции содержит лишь комментарий
...
, фактическая реализация слишком сложна (пожалуйста, не пытайтесь пока ее написать). Сначала разместим объявления в заголовочном файле
Chrono.h
.

// файл Chrono.h

#include "Chrono.h"

namespace Chrono {

  • Читать дальше
  • 1
  • ...
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: