Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Передача объекта по ссылке
Оператор ссылки описан в главе 9, "Второе знакомство с указателями", и может применяться для пользовательских объектов так же, как и для всех остальных.
//Все то же самое, но осуществляем передачу по ссылке void refS)
refS.gpa = 3.0;
} = 10;
4.0); //вызываем функцию-член Student s; int argc, char* {
return 0; } В этой программе в функцию someFn () передается не копия объекта, а ссылка на него. Изменения, внесенные функцией s ome Fn () в сохраняются внутри in (). Передача объекта по ссылке фактически передает в функцию адрес объекта s; при этом C++ самостоятельно разыменовывает переданный указатель.
164 Часть "Классическое" программирование Проблемы, возникающие при работе с указателями на простые переменные, рас- пространяются и на указатели на объекты. В частности, необходимо гарантировать, что указатель ссылается на существующий корректный объект. Так, нельзя возвращать указатель на локально определенный объект, как это сделано в данном примере: MyClass* { //эта функция не будет работать правильно MyClass MyClass* = return } После возврата из объект выходит из области видимости, а значит, который возвращает (), указывает на несуществующий объект. Использование кучи позволяет решить эту проблему: MyClass*
pMC new MyClass; return pMC; }
С помощью кучи можно выделять память для объектов в самых разнооб- разных ситуациях.
использованиесвязанныхсписков Связанный список является второй по распространенности структурой после мас- сива. Основным преимуществом связанного списка служит отсутствие необходимости задавать фиксированный размер на этапе компиляции: связанный список может уменьшаться и увеличиваться в зависимости от потребностей программы. Цена такой гибкости — сложность обращения, поскольку использовать элементы связанного спи- ска гораздо сложнее, чем элементы массива.
Массив Массив очень удобен для хранения набора объектов, так как позволяет просто и быстро обратиться к отдельным его элементам: MyClass //выделяем место под 100 элементов [п ; / к элементу списка Однако у массивов есть много весомых недостатков. Основным недостатком массивов является фиксированность их длины. Можно спрогнозировать количество элементов в массиве, необходимое для работы програм- мы, однако, будучи однажды определенным, это количество не может быть изменено.
( //создаем массив из п объектов //MyClass MyClass* pMC = new //теперь длина массива не может
Глава 15. Создание указателей на объекты 165 //быть изменена } Кроме того, все элементы массива должны быть одного типа. Невозможно хранить объекты типа и YourClass в одном массиве. И наконец, крайне трудно вставить объект в середину массива. Для добавления или удаления объекта программа должна перенести соседние элементы вперед или назад, чтобы создать или уничтожить пустое место в середине массива. (Представьте себе про- цесс вставки дома внутрь застроенного квартала, и вы поймете, о чем я говорю.) Однако существует и альтернативная структура данных, лишенная указанных недос- татков. Конструкция, которая может заменить массив, называется связанным списком.
Связанный список Дети, держащие друг друга за руки и переходящие дорогу, используют тот же принцип, что и связанный список. В связанном списке каждый объект связан со сле- дующим объектом в цепочке. Учитель в этом случае представляет собой головной элемент, указывающий на первый элемент списка. Не всякий класс может быть использован для создания связанного списка. ваемый класс объявляется так, как показано в приведенном ниже фрагменте. class LinkableClass
LinkableClass* //прочие члены класса }; Ключевым в этом классе является указатель на объект класса LinkableClass. На первый взгляд несколько необычно выглядит то, что класс содержит указатель сам на себя. В действительности в этом объявлении подразумевается, что каждый объект класса содержит указатель на другой объект этого же класса. Указатель pNext и есть тот элемент, с помощью которого дети объединяются в це- почки. Фигурально выражаясь, можно сказать, что список детей состоит из некото- рого количества объектов, каждый из которых имеет тип "ребенок". Каждый ребенок указывает на следующего ребенка. Головной указатель является указателем типа LinkableClass* , и если продолжать аналогию с цепочкой детей, то можно сказать, что учитель указывает на объект класса "ребенок" (любопытно отметить, что сам учитель не является ребенком — головной указатель не обязательно должен иметь тип LinkableClass). забывайте инициализировать указатели значением 0. Указатель, со- держащий ноль, называется "пустым". Обычно попытка обращения по адресу 0 вызывает аварийную остановку программы.
Преобразование целочисленного нуля в тип не обяза- тельно. C++ воспринимает 0 как значение любого типа (в частности, как "универсальный указатель").
Приведенная ниже простая функция, добавляющая переданный ей аргумент в на- чало списка, поможет вам разобраться со связанными списками. void pLC) { pLC->pNext = pHead pHead = pLC;
Часть III, "Классическое" программирование Другие операции над связанным списком Добавление объекта в начало списка является самой простой операцией со связан- ным списком. Гораздо сложнее добавить элемент в конец списка: void pLC) { на начало списка pCurxent = //будем просматривать список, пока не найдем элемент списка — он должен содержать //О указателе != f ) 0] { pCurrent pCurrent->pNext; } //теперь заставим этот объект указывать на pCurrent->pNext = pLC; //присвоим 0 указателю на следующий объект //в новом конечном пометив его //как последний в списке = } Тело функции addTail () начинается с просмотра всего списка с самого начала до элемента, значение поля которого равно нулю. Этот элемент и является послед- ним в списке. После этого функция addTail () добавляет объект pLC* к концу списка. (В действительности приведенная функция содержит одну ошибку. Кроме провер- ки элементов списка на равенство нулю, необходимо проверять и головной элемент списка pHead. Ноль в pHead означает, что список пуст.) Функция remove () схожа с предыдущей. Она удаляет указанный объект из списка и возвращает 1, если удаление прошло без ошибок, и 0 в противном случае. void pLC) { pCurrent = pHead; //если список пуст, мы не найдем в нем *pLC if (LinkableClass*) 0) { return 0; }
весь список до конца в поисках элемента while { //если следующий объект является искомым объектом { заставим текущий объект указывать //на следующий за ним pCurrent->pNext = //это не обязательно, но лучше удалить указатель //на следующий объект в удаляемом элементе pLC->pNext = return 1;
return 0; }
Глава 15. Создание указателей на объекты 167 Сначала функция проверяет, не пуст ли список. Если список пуст, функция 0 (поскольку в этом случае объекта *pLC точно нет в списке). Если список не пуст, remove О просматривает все элементы списка, пока не найдет искомый объект. Если функция находит объект, она присваивает текущему указателю pNext значение указателя pNext из найденного объекта. Было бы неплохо, если бы, внимательно рассмотрев приведенный фрагмент, вы могли сказать, в каком случае он будет работать неправильно.
|
Последнее изменение этой страницы: 2019-04-19; Просмотров: 231; Нарушение авторского права страницы