|
Программирование >> Оптимизация возвращаемого значения
Глава 1. Основы Указатели, ссылки, приведение типов, массивы, конструкторы - это то, что составляет основу языка. Все программы на языке С++, за исключением самых простых, используют большую часть названных понятий, а многие программы используют их все. Даже самые знакомые вещи иногда могут нас удивлять. Особенно это справедливо для программистов, переходящих с языка С на С++, так как концепции, на которых базируются понятия ссылок, динамического приведения типов, конструкторов по умолчанию и других, не принадлежащих языку С, обычно не всегда очевидны. Эта глава объясняет разницу между указателями и ссылками и содержит советы, когда следует использовать каждое из этих понятий. В ней также описан новый синтаксис языка С++ для приведения типов и объясняется, чем новый стиль превосходит заменяемый стиль языка С. Кроме того, рассматривается концепция массивов в языке С и концепция полиморфизма в языке С++, а также говорится, почему их никогда не стоит использовать одновременно. Наконец, в ней рассказано о плюсах и минусах конструкторов по умолчанию и предложены пути для обхода ограничений языка, которые требуют существования такого конструктора, даже если это не имеет практического смысла. Следуя советам, приведенным в нижеизложенных правилах, вы сможете создавать такое программное обеспечение, где ваш замысел будет реализован ясно и правильно. Правило 1. Различайте указатели и ссылки Указатель (pointer) и ссылка (reference) существенно отличаются по внешнему виду (указатели используют операторы * (умножить) и -> (стрелка), ссылки используют оператор . (точка)), но применяются для решения одних и тех же задач. И указатели и ссылки позволяют неявно ссылаться на другие объекты. Как же тогда решить, когда применять указатели, а когда ссылки? Во-первых, запомните, что не существует нулевых ссылок. Ссылка должна всегда ссылаться на какой-либо объект. Если ваша переменная обеспечивает доступ к объекту, которого может и не быть, вы должны использовать указатель, потому что это позволит приравнять его нулю. С другой стороны, если переменная должна всегда ссылаться на существующий объект, то есть не должна иметь нулевого значения, то, скорее всего, лучше использовать в качестве такой переменной ссылку. Но подождите! , - воскликнет читатель, - а как же будет работать следующий кусок кода? : char *рс = О; / / Присвоить указателю значение null. charSc rc = *рс; / / Установить ссылку на содержимое нулевого указателя. Надо сказать, это пример самого настоящего безобразия. Результаты работы такой программы не определены: компиляторы могут генерировать программный код, который будет делать все, что угодно. Если у вас возникают подобные проблемы, то лучше вообще отказаться от использования ссылок. В качестве другого выхода вы можете поискать для сотрудничества программистов более высокого класса. В дальнейшем мы не будем считаться с возможным существованием нулевых ссылок. Так как ссылка должна ссылаться на объект, С++ требует ее инициализации: str ing& г s; / / Ошибка! Ссылки должны быть проинициализированы. string S{ xyzzy ); string& rs = s; / / Нормально, rs ссылается на s . Ha указатели таких ограничений не налагается: string *ps; Неинициализированный указатель: допустимо, но рискованно. Невозможность существования нулевых ссылок подразумевает, что использование ссылок более эффективно, чем использование указателей. Корректность ссылки не нужно предварительно проверять: voidprintDouble(const double& rd) { cout << rd; Нет необходимости пpoвepятьrd; } она должна ссылаться на double. Указатели же, наоборот, обычно должны проверяться на равенство нулю: voidprintDouble (const double *pd) { if (pd) { Проверка на значение null. cout << *pd; Другое важное различие между указателями и ссылками состоит в возможности присваивать зтсазателям различные значения для доступа к разным объектам. Ссылка же всегда указывает на один и тот же объект, заданный при ее инициализации: string si( Nancy ) ; strings2( Clancy ); string& rs = si; rs ссылается на si. string *ps = &sl; ps указывает на si. rs = s2; rs все еще ссылается на si, но теперь si имеет значение Clancy . ps = &s2; ps указывает на s2; значение si не изменилось. Вообще говоря, указатель следует использовать, если есть вероятность, что объект, связанный с указателем, отсутствует (в этом случае ему присваивается нулевое значение) или периодически возникает необходимость доступа к разным объектам (в этом случае изменяется значение указателя). Ссылку же следует использовать, если объект, к которому необходимо обеспечить доступ, будет существовать всегда, и не потребуется получить доступ к другому объекту с помощью все той же ссылки. Существует еще одна ситуация, в которой вы должны задействовать ссылки -при реализации некоторых операторов; из них наиболее часто встречается оператор [ ] (скобки). Обычно этот оператор должен вернуть некое значение, которое затем будет использовано как принимающее в операторе присваивания: vector<int>v{10) ; Создаем векторцелых значений размерности 10; векторявляетсяшаблоном из стандартной библиотеки С++ (см.правило 35). v[5] =10; Значение,возвращаемое оператором [],является принимающей стороной оператора присваивания. Если бы оператор [ ] возвращал указатель, то последнюю строку этого кода надо было бы записать так: *V[5] =10; Но создавалось бы ложное впечатление, что v является вектором указателей. Поэтому почти всегда желательно, чтобы оператор [ ] возвращал ссылку. (Интересное исключение из этого правила приведено в правиле 30.) Итак, использование ссылок оправдано, когда доподлинно известно, что объект ссылки существует, когда нет необходимости изменять значение ссылки и при реализации операторов, в которых применение указателей нежелательно из-за синтаксических требований. Во всех других случаях используйте указатели. Правило 2. Предпочитайте приведение типов в стиле С++ Рассмотрим прямое приведение типов. Это почти такой же изгой, как и оператор goto, но тем не менее оно продолжает использоваться, потому что, когда ситуация становится хуже некуда , может оказаться необходимым. Приведение типов в стиле языка С не применяется так широко, как могло бы. Во-первых, это довольно грубый инструмент, практически позволяющий привести произвольный тип к любому другому. Было бы неплохо более точно определять цель каждого приведения. Например, существует большая разница между приведением
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |