|
Программирование >> Программирование на языке c++
комавды #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 является локальным (автоматическим) объектом в
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |