В строке 154 создается третья строка с концевым нулевым символом — tempTwo. В строке 155 с помощью функции strcpy() происходит заполнение буфера строкой символов nice to be here!. В строке 156 с помощью перегруженного оператора += осуществляется конкатенация строки tempTwo к существующей строке s1. Результат выводится на экран в строке 158.
В строке 160 возвращается и выводится на экран пятый символ строки — s1. Затем в строке 161 этот символ замещается другим с помощью неконстантного оператора индексирования ([]). Результат выводится строкой 162, чтобы показать, что символ строки действительно изменился.
В строке 164 делается попытка получить доступ к символу за пределами массива. Возвращается и выводится на печать последний символ строки, как и было предусмотрено при перегрузке оператора индексирования.
В строках 166 и 167 создаются два дополнительных объекта String, и в строке 168 используется перегруженный оператор суммирования. Результат выводится строкой 169.
В строке 171 создается еще один объект класса String — s4. В строке 172 используется оператор присваивания, а строка 173 выводит результат. Оператор присваивания перегружен таким образом, чтобы использовать константную ссылку класса String, объявленную в строке 21, но в данном случае в функцию передается строка с концевым нулевым символом. Разве это допустимо?
Хотя компилятор, ожидая получить объект String, вместо этого получает массив символов, он автоматически проверяет возможность преобразования полученного значения в ожидаемую строку. В строке 12 объявляется конструктор, который создает объект String из массива символов. Компилятор создает временный объект String из полученного массива символов и передает его в функцию оператора присваивания. Такой процесс называется неявным преобразованием. Если бы в программе не был объявлен соответствующий конструктор, преобразующий массивы символов, то для этой строки компилятор показал бы сообщение об ошибке.
Связанные списки и другие структуры
Массивы являются отличными контейнерами для данных самых разных типов. Единственный их недостаток состоит в том, что при создании массива необходимо за- дать его фиксированный размер. Если на всякий случай создать слишком большой массив, то попусту будет потрачено много памяти компьютера. Если сэкономить память, то возможности программы по оперированию данными окажутся ограниченными.
Один из способов решения этой проблемы состоит в использовании связанных списков. Связанный список представляет собой структуру данных, состоящую из взаимосвязанных блоков, каждый из которых может поддерживать структурную единицу
данных. Идея состоит в том, чтобы создать класс, поддерживающий объекты данных определенного типа, такого как CAT или Rectangle, которые, помимо данных, содержали бы также указатели, связанные с другими объектами этого класса. Таким образом, получается класс, содержащий взаимосвязанные объекты, образующие произвольную структуру-список.
Такие объекты называют узлами. Первый узел в списке образует голову, а последний — хвост.
Существует три основных типа связанных списков. Ниже они перечислены в порядке усложнения.
• Однонаправленные списки.
• Двунаправленные списки.
• Деревья.
В однонаправленных связанных списках каждый узел указывает на следующий узел только в одном направлении. Движение по узлам в обратном направлении невозможно. Чтобы найти нужный узел, следует начать с первого узла и двигаться от узла к узлу, подобно кладоискателю, действующему согласно указаниям карты поиска сокровищ: "...от большого камня иди к старому дубу, сделай три шага на восток и начинай копать..." Двунаправленные списки позволяют осуществлять движение в обоих направлениях по цепи. Деревья представляют собой более сложные структуры, в которых один узел может содержать ссылки на два или три следующих узла. Все три типа связанных списков схематично показаны на рис. 12.5.
Общие представления о связанных списках
В данном разделе обсуждаются основные моменты создания сложных структур и, что еще более важно, возможности использования в больших проектах наследования, полиморфизма и инкапсуляции.
Делегирование ответственности
Основная идея объектно-ориентированного программирования состоит в том, что каждый объект специализируется в выполнении определенных задач и передает другим объектам ответственность за выполнение тех задач, которые не соответствуют их основному предназначению.
Читать дальше