char c = name[10]; // указание неправильного индекса массива
// порождает неопределенное поведение
Дабы подчеркнуть, что результаты неопределенного поведения невозможно предсказать и что они могут быть весьма неприятны, опытные программисты на C++ часто говорят, что программы с неопределенным поведением могут стереть содержимое жесткого диска. Это правда: такая программа
Иной термин, который может смутить программистов, пришедших из других языков, – это интерфейс.
В Java и. NET-совместимых языках интерфейсы являются частью языка, но в C++ ничего подобного нет, хотя в правиле 31 рассматривается некоторое приближение. Когда я использую термин «интерфейс», то обычно имею в виду сигнатуры функций, доступные члены класса («открытый интерфейс», «защищенный интерфейс», «закрытый интерфейс») или выражения, допустимые в качестве параметров типа для шаблонов (см. правило 41). То есть под интерфейсом я понимаю общую концепцию проектирования.Понятие клиент
– это нечто или некто, использующий написанный вами код (обычно через интерфейсы). Так, например, клиентами функции являются ее пользователи: части кода, которые вызывают функцию (или берут ее адрес), а также люди, которые пишут и сопровождают такой код. Клиентами класса или шаблона являются части программы, использующие этот класс или шаблон, а равно программисты, которые пишут или сопровождают эти части. Когда речь заходит о клиентах, я обычно имею в виду программистов, поскольку именно они могут быть введены в заблуждение или недовольство плохо разработанным интерфейсом. Коду, который они пишут, такие эмоции недоступны.Возможно, вы не привыкли думать о клиентах, но я постараюсь убедить вас в необходимости облегчить им жизнь, насколько это возможно. В конце концов, вы сами – клиент программного обеспечения, которое разрабатывал кто-то другой. Ведь вы хотели бы, чтоб его авторы облегчили вам работу? Помимо того, рано или поздно вы окажетесь в положении, когда сами станете клиентом собственного кода (то есть будете использовать код, написанный вами), и тогда оцените, что при разработке интерфейсов нужно помнить об интересах клиентов.
В этой книге я часто обращаю внимание на различие между функциями и шаблонами функций, а также между классами и шаблонами классов. Это не случайно, ведь то, что справедливо для одного, часто справедливо и для другого. В ситуациях, когда это не так, я делаю различие между классами, функциями и шаблонами, из которых порождаются классы и функции.
Соглашения об именах
Я пытался выбирать осмысленные имена для объектов, классов, функций, шаблонов и т. п., но семантика некоторых придуманных мной имен может быть для вас неочевидна. Например, я часто использую для параметров имена lhs и rhs. Имеется в виду соответственно «левая часть» (left-hand side) и «правая часть» (right-hand side). Эти имена обычно употребляются в функциях, реализующих бинарные операторы, то есть operator== и operator*. Например, если a и b – объекты, представляющие рациональные числа, и если объекты класса Rational можно перемножать с помощью функции-нечлена operator* (подобный случай описан в правиле 24), то выражение
a*b
эквивалентно вызову функции:
operator*(a, b);
В правиле 24 я объявляю operator* следующим образом:
const Rational operator*(const Rational lhs, const Rational rhs);
Как видите, левый операнд – a – внутри функции называется lhs, а правый – b – rhs.
Для функций-членов аргумент в левой части оператора представлен указателем this, а единственный оставшийся параметр я иногда называю rhs. Возможно, вы заметили это в объявлении некоторых функций-членов класса Widget в примерах выше. «Widget» не значит ничего. Это просто имя, которое я иногда использую для того, чтобы как-то назвать пример класса. Оно не имеет никакого отношения к элементам управления (виджетам), применяемым в графических интерфейсах (GUI).
Часто я именую указатели, следуя соглашению, с соответствии с которым указатель на объект типа T называется pt («pointer to T»). Вот некоторые примеры:
Widget *pw; // pw = указатель на Widget
class Airplane;
Airplane *pa; // pa = указатель на Airplane
class GameCharacter;
GameCharacter *pgc; // pgc = указатель на GameCharacter
Похожее соглашение применяется и для ссылок: rw может быть ссылкой на Widget, а ra – ссылкой на Airplane.