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

1 ... 27 28 29 [ 30 ] 31 32 33 ... 227


36 Самоучитель C++,

str. set (s) ; .. : -i. /

return str; i . К --

int mainO

samp ob;

/ / возвращаемое значение присваивается объекту ob ob = ii-LuL О; Это ведет к ошибке оЬ.show();

return 0; 4:.f;F

Здесь показан результат работы программы:

Введите строку: Привет Освобождение памяти по адресу s Освобождение памяти по адресу s Привет

Освобождение памяти по адресу s

Null pointer assignment , .

Обратите внимание, что деструктор класса samp вызывается трижды. Первый когда локальный объект выходит из области видимости при возвращении функцией input() своего значения. Второй раз ~samp() вызывается тогда, когда удаляется временный объект, возвращаемый функцией input().

Запомните, когда объект возвращается функцией, автоматически генерируется невидимый (для вас) временный объект, который и хранит возвращаемое значение. В этом случае временный объект - это просто копия объекта str, являющегося возвращаемым значением функции. Следовательно, после того как функция возвратила свое значение, выполняется деструктор временного объекта. И наконец, при завершении программы вызывается деструктор объекта ob в функции mainO-

Проблема в этой ситуации в том, что при первом выполнении деструктора память, выделенная для хранения вводимой с помощью функции input() строки, освобождается. Таким образом, при двух других вызовах деструктора класса samp не только делается попытка освободить уже освобожденный блок динамической памяти, но в процессе работы происходит разрушение самой системы динамического распределения памяти и, как доказательство этому, появляется сообщение Null pointer assignment . (В зависимости от вашего компилятора, модели используемой памяти и тому подобного при попытке выполнить программу это сообщение может и не появиться.)

Ключевым моментом в понимании описанной в этом примере,

является то, что при возвращении функцией объекта для временного объекта, который и является возвращаемым значением функции, вызывается дест-



руктор. (Как вы узнаете в главе 5, для решения проблемы в такой ситуации можно воспользоваться конструктором копий.)

1. Для внимательного изучение отросп когда при возвращении функцией объекта для него вызываются конструктор и структр. создайте класс who. Конструктор who должен иметь один символьный аргумент, который будет использоваться для идентификации объекта. При создании объекта конструктор должен выводить на экран сообщение:

Создание объекта who #х ! r.i i

где х - идентифицирующий символ, свой для каждого объекта. При удалении объекта на экран должно выводиться примерно такое сообщение:

Удаление объекта who ttx

где х снова идентифицирующий символ. Наконец, создайте функцию make who(), которая возвращает объект who. Присвойте каждому объекту

уникальное имя. Проанализируйте выводимый на экран результат работы

программы.

2. Продумайте ситуацию, в которой, как и при освобождении динамической памяти, возвращать объект из функции было бы также ошибочно.

3.4. Дружественные функции: обзор

Возможны ситуации, когда для получения доступа к закрытым членам класса вам понадобится функция, не являющаяся членом этого класса. Для достижения этой цели в C++ поддерживаются дружественные функции (friend functions). Дружественные функции не являются членами класса, но тем не менее имеют доступ к его закрытым элементам.

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

Дружественная функция задается так как обычная, не являющаяся членом класса, функция. Однако в объявление класса, для которого функция будет дружественной, необходимо включить ее прототип, перед которым ставится ключевое слово friend. Чтобы понять, как работает дружественная функция, рассмотрим следующую короткую программу:



gg Самоучитель C++

II Пример использования дружественной функции

tinclude <iostrearn> . . , . -

usin space std;

class myclass (

int n, d; public:

гаусТр.яя Ont- i, int j) { n = i; d - j; } объявление дружественной функции для класса myclass friend int igfactor (myclass ob) ; ...

Здесь представлено определение дружественной функции. Она возвращает истину, если n делится без остатка на d. Отметьте, что кочевое слово friend в оеделении функции LOf (; не используется.

int isfactor (myclass ob) , .

if(!(ob.n % ob.d)) return 1; ;

else return 0;

myclass

if (isfactor(obl) cou << 10 без остатка делится на 2\n ; else cou 10 без остатка не делится на 2\п ;

f

if (isfactor(оЬ2) cou 13 без остатка делится на 3\п ;

else cou 13 бе остатка не делится на 3\п ;

return 0;

В этом примере в объявлении класса myclass объявляются конструктор и дружественная функция isfactor(). Поскольку функция isfactor() дружественна для класса myclass, то функция isfactorQ имеет доступ к его закрытой части. Поэтому внутри функции isfactor() можно непосредственно ссылаться на объекгы оЬ.п и ob.d.

Важно понимать, что дружественная функция не является членом класса, для которого она дружественна. Поэтому невозможно вызвать дружественную функцию, используя имя объекта и оператор доступа к члену класса (точку или стрелку). Например, по отношению к предыдущему примеру эта инструкция неправильна:

оЫ. is factor О ; неправильно ctor () - это не функция-член



1 ... 27 28 29 [ 30 ] 31 32 33 ... 227

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