(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Краткий вопросник по C++. Часть 1 (FAQ)

Источник: hardline
Автором английской версии является Marshall Cline (cline@parashift.com), автором перевода - Ярослав Миронов (slava_mironov@mail.ru)

Этот документ является переводом сборника ответов на часто задаваемые вопросы группы новостей comp.lang.c++.

[8.1] Что такое ссылка?

Ссылка - это псевдоним (другое имя) для объекта.

Ссылки часто используются для передачи параметра по ссылке:

    void swap(int& i, int& j)
    {
        int tmp = i;
        i = j;
        j = tmp;
    }

    int main()
    {
        int x, y;
        // ...
        swap(x,y);
    }

В этом примере i и j - псевдонимы для переменных x и y функции main . Другими словами, i - это x . Не указатель на x и не копия x , а сам x . Все, что вы делаете с i , проделывается с x , и наоборот.

Вот таким образом вы как программист должны воспринимать ссылки. Теперь, рискуя дать вам неверное представление, несколько слов о том, каков механизм работы ссылок. В основе ссылки i на объект x - лежит, как правило, просто машинный адрес объекта x . Но когда вы пишете i++ , компилятор генерирует код, который инкрементирует x . В частности, сам адрес, который компилятор использует, чтобы найти x , остается неизменным. Программист на С может думать об этом, как если бы использовалась передача параметра по указателю, в духе языка С, но, во-первых, & (взятие адреса) было бы перемещено из вызывающей функции в вызываемую, и, во-вторых, в вызываемой функции были бы убраны * (разыменование). Другими словами, программист на С может думать об i как о макроопределении для (*p) , где p - это указатель на x (т.е., компилятор автоматически разыменовывает подлежащий указатель: i++ заменяется на (*p)++ , а i = 7 на *p = 7 ).

Важное замечание: несмотря на то что в качестве ссылки в окончательном машинном коде часто используется адрес, не думайте о ссылке просто как о забавно выглядящем указателе на объект. Ссылка - это объект. Это не указатель на объект и не копия объекта. Это сам объект.

[8.2] Что происходит в результате присваивания ссылке?

Вы меняете состояние ссыльного объекта (того, на который ссылается ссылка).

Помните: ссылка - это сам объект, поэтому, изменяя ссылку, вы меняете состояние объекта, на который она ссылается. На языке производителей компиляторов ссылка - это lvalue (left value - значение, которое может появиться слева от оператора присваивания).

[8.3] Что происходит, когда я возвращаю из функции ссылку?

В этом случае вызов функции может оказаться с левой стороны оператора (операции) присваивания.

На первый взгляд, такая запись может показаться странной. Например, запись f() = 7 выглядит бессмысленной. Однако, если a - это объект класса Array , для большинства людей запись a[i] = 7 является осмысленной, хотя a[i] - это всего лишь замаскированный вызов функции Array::operator[](int) , которая является оператором обращения по индексу для класса Array :

    class Array {
    public:
        int size() const;
        float& operator[] (int index);
        // ...
    };

    int main()
    {
        Array a;
        for (int i = 0; i < a.size(); ++i)
            a[i] = 7; // В этой строке вызывается Array::operator[](int)
    }

[8.4] Как можно переустановить ссылку, чтобы она ссылалась на другой объект?

Невозможно в принципе.

Невозможно отделить ссылку от ее объекта.

В отличие от указателя, ссылка, как только она привязана к объекту, не может быть "перенаправлена" на другой объект. Ссылка сама по себе ничего не представляет, у нее нет имени, она сама - это другое имя для объекта. Взятие адреса ссылки дает адрес объекта, на который она ссылается. Помните: ссылка - это объект, на который она ссылается.

С этой точки зрения, ссылка похожа на const указатель [ 18.5 ], такой как int* const p (в отличие от указателя на const [ 18.4 ], такого как const int* p ). Несмотря на большую схожесть, не путайте ссылки с указателями - это не одно и то же.

[8.5] В каких случаях мне стоит использовать ссылки, и в каких - указатели?

Используйте ссылки, когда можете, а указатели - когда это необходимо.

Ссылки обычно предпочтительней указателей, когда вам ненужно их "перенаправлять" [ 8.4 ]. Это обычно означает, что ссылки особенно полезны в открытой (public) части класса. Ссылки обычно появляются на поверхности объекта, а указатели спрятаны внутри.

Исключением является тот случай, когда параметр или возвращаемый из функции объект требует выделения "охранного" значения для особых случаев. Это обычно реализуется путем взятия/возвращения указателя, и обозначением особого случая при помощи передачи нулевого указателя (NULL). Ссылка же не может ссылаться на разыменованный нулевой указатель.

Примечание: программисты с опытом работы на С часто недолюбливают ссылки, из-за того что передача параметра по ссылке явно никак не обозначается в вызывающем коде. Однако с обретением некоторого опыта работы на С++, они осознают, что это одна из форм сокрытия информации, которая является скорее преимуществом, чем недостатком. Т.е., программисту следует писать код в терминах задачи, а не компьютера (programmers should write code in the language of the problem rather than the language of the machine).

РАЗДЕЛ [9]: Встроенные ( inline ) функции

[9.1] Что такое встроенная функция?

Встроенная функция - это функция, код которой прямо вставляется в том месте, где она вызвана. Как и макросы, определенные через #define , встроенные функции улучшают производительность за счет стоимости вызова и (особенно!) за счет возможности дополнительной оптимизации ("процедурная интеграция").

[9.2] Как встроенные функции могут влиять на соотношение безопасности и скорости?

В обычном С вы можете получить "инкапсулированные структуры", помещая в них указатель на void , и заставляя его указывать на настоящие данные, тип которых неизвестен пользователям структуры. Таким образом, пользователи не знают, как интерпретировать эти данные, а функции доступа преобразуют указатель на void к нужному скрытому типу. Так достигается некоторый уровень инкапсуляции.

К сожалению, этот метод идет вразрез с безопасностью типов, а также требует вызова функции для доступа к любым полям структуры (если вы позволили бы прямой доступ, то его мог бы получить кто угодно, поскольку будет известно, как интерпретировать данные, на которые указывает void* . Такое поведение со стороны пользователя приведет к сложностям при последующем изменении структуры подлежащих данных).

Стоимость вызова функции невелика, но дает некоторую прибавку. Классы С++ позволяют встраивание функций, что дает вам безопасность инкапсуляции вместе со скоростью прямого доступа. Более того, типы параметры встраиваемых функций проверяются компилятором, что является преимуществом по сравнению с (?)сишными #define макросами.

[9.3] Зачем мне использовать встроенные функции? Почему не использовать просто #define макросы?

Поскольку #define макросы опасны [ 9.3 ], опасны [ 34.1 ], опасны [ 34.2 ], опасны [ 34.3 ].

В отличие от #define макросов, встроенные ( inline ) функции неподвержены известным ошибкам двойного вычисления, поскольку каждый аргумент встроенной функции вычисляется только один раз. Другими словами, вызов встроенной функции - это то же самое что и вызов обычной функции, только быстрее:

	// Макрос, возвращающий модуль (абсолютное значение) i
	#define unsafe(i) 		( (i) >= 0 ? (i) : -(i) )

	// Встроенная функция, возвращающая абсолютное значение i
	inline
	int safe(int i)
	{
		return i >= 0 ? i : -i;
	}

	int f();

	void userCode(int x)
	{
		int ans;
		ans = unsafe(x++); // Ошибка! x инкрементируется дважды
		ans = unsafe(f()); // Опасно! f() вызывается дважды
		ans = safe(x++); // Верно! x инкрементируется один раз
		ans = safe(f()); // Верно! f() вызывается один раз
	}

Также, в отличие от макросов, типы аргументов встроенных функций проверяются, и выполняются все необходимые преобразования.

Макросы вредны для здоровья; не используйте их, если это не необходимо.

Читать часть 2

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 21.08.2009 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
TeeBI for RAD Studio Suite with source code single license
Allround Automation PL/SQL Developer - Unlimited license
Panda Internet Security - ESD версия - на 1 устройство - (лицензия на 1 год)
SAP Crystal Reports XI R2 Dev 2006 INTL WIN NUL License (Version 11)
ABViewer Professional пользовательская
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Программирование на Microsoft Access
CASE-технологии
OS Linux для начинающих. Новости + статьи + обзоры + ссылки
СУБД Oracle "с нуля"
Мир OLAP и Business Intelligence: новости, статьи, обзоры
Работа в Windows и новости компании Microsoft
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100