Г. Шилтд - Самоучитель C++ (PDF) (1114887), страница 44
Текст из файла (страница 44)
Попытайтесь адаптировать программы предыдущей главы для работы с файлами.Проверка усвоенияматериала главы;—:—"""l[^NjТеперь вам необходимо выполнить следующие упражнения и ответить навопросы.1. Создайте манипулятор для вывода трех символов табуляции и установкиширины поля равной 20. Продемонстрируйте работу манипулятора.2.
Создайте манипулятор для ввода, который должен считывать и отбрасывать все неалфавитные символы. При считывании первого алфавитногосимвола, манипулятор должен возвратить его во входной поток и закончить работу. Назовите манипулятор findalpha.3. Напишите программу копирования текстового файла.
При копированииизмените регистр всех букв.Глава 9. Дополнительные возможности ввода/вывода в C++3014. Напишите программу, которая считывает текстовый файл, а затем сообщает, сколько раз каждая буква алфавита появляется в файле.5. Если вы еще этого не сделали, добавьте в ваши решения упражнений 3 и4 полный контроль ошибок.6. Какая функция перемещает указатель считывания? Какая функция перемещает указатель записи?Проверка усвоенияматериала в целомВ этом разделе проверяется, хорошо ли вы усвоили материал этой и предыдущих глав.1.
Ниже приведена переработанная версия класса inventory из предыдущейглавы. Добавьте функции storeQ и retrieveQ. Затем создайте небольшойфайл, содержащий несколько инвентарных записей. Далее, используяпроизвольный доступ, по номеру записи отобразите на экране информацию об одном из элементов.ttinclude <fstream>ttinclude <iostream>ttinclude <cstring>using namespace std;ttdefine SIZE 40class inventory {char itemfSIZE]; // название предметаint onhand;// количество выданных на руки экземпляровdouble cost;// цена предметаpublic:inventory(char *i, int o, double c);strcpy(item, i);onhand = o;cost = c;void store(fstream sstream);void retrieve(fstream sstream);friend ostream &operator« (ostream sstream, inventory oVfriend istream &operator»(istream sstream, inventory &ob) ;};ostream &operator« (ostream &stream, inventory ob)stream « ob.item « ": " « ob.onhand;stream « "на руках по цене ." « ob.cost « '\n';302Самоучитель C++return stream;)istream «operator»{istreara &stream, inventory sob){cout « "Введите название предмета: ";stream » ob.item;cout « "Введите число выданных экземпляров: ";stream » ob.onhand;cout « "Введите стоимость экземпляра: ";stream » ob.cost;return stream;'2.
Необязательное задание. Создайте класс stack для хранения символов вфайле, а не в массиве.Глава 10ВиртуальныефункцииВ этой главе рассматривается следующий важный аспект C++: виртуальныефункции (virtual functions). Виртуальные функции важны потому, что онииспользуются для поддержки динамического полиморфизма (run-time polymorphism).
Как вы знаете, в C++ полиморфизм поддерживается двумя способами. Во-первых, при компиляции он поддерживается посредствомперегрузки операторов и функций. Во-вторых, во время выполнения программы он поддерживается посредством виртуальных функций. Здесь выузнаете, как с помощью динамического полиморфизма можно повыситьгибкость программ.Основой виртуальных функций и динамического полиморфизма являютсяуказатели на производные классы. Поэтому эта глава начинается с обсуждения указателей на производные классы.Повторение пройденногоПеред тем как продолжить, необходимо правильно ответить на следующиевопросы и сделать упражнения.1. Создайте манипулятор для вывода чисел в научной нотации с символомЕ в верхнем регистре.2. Напишите программу для копирования текстового файла.
В процессе копирования преобразуйте каждый символ табуляции в соответствующеечисло пробелов.3. Напишите программу для поиска в текстовом файле слова, заданного вкомандной строке. После выполнения программы на экране должно появиться число, обозначающее, сколько раз данное слово найдено в файле.Для простоты считаем следующее: все, что с обеих сторон окружено пробелами, есть слово.4. Напишите инструкцию, которая устанавливает указатель записи на 234-йбайт в файле, связанном с потоком out.5. Какие функции выдают информацию о состоянии системы ввода/выводаC++?Самоучитель C++3046.
Приведите хотя бы одно преимущество от использования функций ввода/вывода C++ по 'сравнению с соответствующими функциями системыввода/вывода языка С.10.1. Указатели на производные классыХотя в главе 4 довольно обстоятельно обсуждались указатели C++, одна ихспецифическая особенность до сих пор опускалась, поскольку она тесносвязана с виртуальными функциями. Этой особенностью является следующее: указатель, объявленный в качестве указателя на базовый класс, такжеможет использоваться, как указатель на любой класс, производный от этогобазового.
В такой ситуации представленные ниже инструкции являютсяправильными:base *p; // указатель базового классаbase base_ob; // объект базового классаderived derived_ob; // объект производного класса,// Естественно, что указатель р может указывать// на объект базового классар = &base_ob; // указатель р для объекта базового класса// Кроме базового класса указатель р может указывать// на объект производного классар = &derived_ob; // указатель р для объекта производного классаКак отмечено в комментариях, указатель базового класса может указыватьна объект любого класса, производного от этого базового и при этом ошибка несоответствия типов генерироваться не будет.Для указания на объект производного класса можно воспользоваться указателем базового класса, при этом доступ может быть обеспечен только к темобъектам производного класса, которые были унаследованы от базового.Объясняется это тем, что базовый указатель "знает" только о базовом классеи ничего не знает о новых членах, добавленных в производном классе.Указатель базового класса можно использовать для указания на объект производного класса, но обратный порядок недействителен.
Указатель производного класса нельзя использовать для доступа к объектам базового класса.(Чтобы обойти это ограничение, можно использовать приведение типов, нона практике так действовать не рекомендуется.)И последнее: запомните, что арифметика указателей связана с типом данных (т. е. классом), который задан при объявлении указателя. Таким образом, если указатель базового класса указывает на объект производногокласса, а затем инкрементируется, то он уже не будет указывать на следующий объект производного класса. Этот указатель будет указывать на следующий объект базового класса. Помните об этом.Глава 10. Виртуальные функции305Примеры1. В этой короткой программе показано, как указатель базового класса можетиспользоваться для доступа к объекту производного класса:// Демонстрация указателя на объект производного класса#include <iostreara>using namespace std;class base {int x;public:void setx(int i) { x = i; }int getx0 { return x; }class derived: public base {int y;public :void sety(int i) { у = i; }int getyf) (return y; }int mambase *p;// указатель базового классаbase b_ob;// объект базового классаderived d_ob; // объект производного класса// использование указателя р// для доступа к объекту базового классар = &b_ob;p->setx(10); // доступ к объекту базового классаcout « "Объект базового класса х: " « p->getx() « '\п';// использование указателя р// для доступа к объекту производного классар = &d_ob;// указывает на объект производного классаp->setx(99); // доступ к объекту производного класса//т.
к. р нельзя использовать для установки у,// делаем это напрямуюd_ob.sety (88) ;cout « "Объект производного класса х: " « p->getx ( ) « ' ';cout « "Объект производного класса у: " « d_ob,gety() « '\п'return 0;306Самоучитель C++Нет смысла использовать указатели на объекты базового класса так, как показано в этом примере. Однако в следующем разделе вы увидите, почему для объектов производного класса столь важны указатели на объекты базового класса.1. Попытайтесь запустить рассмотренную выше программу и поэкспериментируйте с ней.
Например, попробуйте, объявив указатель на производныйкласс, получить доступ к объекту базового класса.10.2. Знакомствос виртуальными функциямиВиртуальная функция (virtual function) является членом класса. Она объявляется внутри базового класса и переопределяется в производном классе. Длятого, чтобы функция стала виртуальной, перед объявлением функции ставится ключевое слово virtual.
Если класс, содержащий виртуальную функцию, наследуется, то в производном классе виртуальная функцияпереопределяется. По существу, виртуальная функция реализует идею "одининтерфейс, множество методов", которая лежит в основе полиморфизма.Виртуальная функция внутри базового класса определяет вид интерфейсаэтой функции.
Каждое переопределение виртуальной функции в производном классе определяет ее реализацию, связанную со спецификой производного класса. Таким образом, переопределение создает конкретный метод.При переопределении виртуальной функции в производном классе, ключевое слово virtual не требуется.Виртуальная функция может вызываться так же, как и любая другая функция-член. Однако наиболее интересен вызов виртуальной функции черезуказатель, благодаря чему поддерживается динамический полиморфизм. Изпредыдущего раздела вы знаете, что указатель базового класса можно использовать в качестве указателя на объект производного класса.
Если указатель базового класса ссылается на объект производного класса, которыйсодержит виртуальную функцию и для которого виртуальная функция вызывается через этот указатель, то компилятор определяет, какую версиювиртуальной функции вызвать, основываясь при этом на типе объекта, накоторый ссылается указатель. При этом определение конкретной версиивиртуальной функции имеет место не в процессе компиляции, а в процессевыполнения программы.