Программирование >>  Программирование на языке c++ 

1 ... 152 153 154 [ 155 ] 156 157 158 159


комавды #else нет, то #endif). Приведенные конструкции (#if, #ifdef, #ifndef) могут вкладываться одна в другую. Директива

#undef идентификатор

приводргг к тому, что указанный идентификатор начинает считаться неопределенным, т. е. не подлежащим замене.

Основное внимание в приложении уделено конструкциям языка С, использованным в этой книге. Ограниченный объем приложения не позволяет рассмотреть язык С более подробно. При необходимости более детального его изучения рекомендуем обратиться к соответствующей литературе [1, 4, 10, 15].

2. Некоторые особенности использования базовых конструкций языка С++

2.1. Значения, указатели и ссылки. Язык С++ поддерживает непосредственный (прямой) и косвенный доступ к объектам. Объект рассматривается как некоторое значение, доступ к которому осуществляется либо непосредственно (через имя этого объекта), либо косвенно (через указатели и ссылки). Разница между указателем и ссылкой заключается в том, что программист может использовать ссылку как обычный объект, несмотря на то, что к объекту будет производиться косвенный доступ, в то время как указателю необходимо присвоить явно значение адреса объекта. После компиляции ассемблерный код для указателей и ссылок будет одинаковым. Ссылка - это подразумеваемый указатель. Указатель требует явного описания. Рассмотрим пример:

void main(void) { int i=3;

int &j=i; j - это ссылка (второе имя) объекта i j=2; }

После выполнения присваивания (j=2) объект i также будет иметь значение 2. В приведенной ниже программе, где используется указатель, компилятор построит тот же ассемблерный код.

void main(void)



{ int i=3;

int *j=&i; j - это указатель на объект i

*j=2; }

Использование ссылок иногда может приводить к неожиданным результатам. Рассмотрим пример:

int F(int& ri)

{ ++r\; return ri; };

void main(void)

{ int m1=1;

cout F(m1) endl; Результат: 2

cout ml endl; } Результат: 2

В примере в функцию F передана ссылка на объект ml. Функция F изменила значение объекта ml косвенно через ссылку на этот объект. Использование ссьшок позволяет нелегально изменить данные даже в секции private некоторого класса (см., например, [16]). Поэтому предпочтительнее избегать использования ссылок на объекты базовых типов, таких как int или char. В то же время ссылки на новые типы данных (на объекты классов) могут оказаться очень эффективными.

Рассмотрим следующее присваивание: X=Y;

Это присваивание является правильным (корректным), если выражение в левой части дает lvalue (left value - левое значение, которое является адресом) и выражение в правой части дает rvalue (right value - правое значение, которое является допустимым значением для заданного типа). В результате значение из правой части будет скопировано в память по адресу, заданному в левой части. Поскольку ссылка - это lvalue, ее можно записать в левой части рассмотренного выражения (т.е. на место переменной X). Передача в функцию параметра v по значению приводит к тому, что копия этого значения (rvalue) будет сохранена в стеке функции. Новая функция не имеет прямого доступа к значению v в старой функции (в функции, из которой вызвана новая функция). Передача в функцию ссылки pv приводит к тому, что копия ссылки, lvalue (левое значение), которое является адресом, а не значением, будет сохранена в стеке функции. Таким обра-



зом, новая функция имеет доступ к значению v в старой функции через ссылку pv на это значение (т.е. через адрес объекта v).

Функция может вернуть ссылку после завершения. В результате, функцию можно записать в левой части присваивания. Если функция возвращает rvalue, то ее нельзя записать в левой части присваивания. Использование ссылок для возвращаемых значений иногда упрощает построение программ [16]. Поскольку ссьшка - это результат, который возвращается из функции, возвращаемое значение не может быть автоматической (локальной) переменной. В противном случае после завершения функции мы может получить ссылку на разрушенный (не существующий) локальный объект. Поскольку функцию можно использовать более одного раза в одном и том же выражении (например, f(...)+f(...)+f(...)+...), возвращаемое значение не может быть статической локальной переменной.

Рассмотрим следующую программу:

class X { int *i;

public:

X(void) { i=new int[2]; i[0]=0; i[1]=1; } ~X(void) { delete[] i; } void displayO

{ cout i[0] \t i[1] endl; } }; void f(X,x)

{ int *j = new int[2];

выполнение каких-то действий

void main(void)

{ X о; o.displayO;

f(o); автоматический вызов деструктора

O.displayO;

} автоматический вызов деструктора

Здесь в функцию F передается значение типа X. Если даже наша функция ничего не делает, мы будем иметь ошибку, связанную с динамическим выделением и освобождением памяти. Рассмотрим следующий вызов функции: f(o);. Параметр о функции f является локальным (автоматическим) объектом в



1 ... 152 153 154 [ 155 ] 156 157 158 159

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика