Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
СОЗДАНИЕ СОБСТВЕННЫХ ОПЕРАТОРОВ newИ delete
Как вы знаете, C++ позволяет вашим программам перегружать операторы. Аналогично вы можете перегрузить операторы new и delete, чтобы изменить их поведение. Например, предположим, что вы выделяете 100 байт памяти для хранения супер-секретных данных о вашей компании. Когда вы в дальнейшем освобождаете эту память с помощью оператораdelete, освобождается буфер, который содержал эту память, т.е. те самые 100 байт, содержащие супер-секретные данные о вашей компании. Предположим, корпоративный шпион (и программист) имеет доступ к вашему компьютеру, его программа теоретически может распределить тот же 100-байтный массив в памяти вашего компьютера и изучить ваши супер-секреты. Перегружая оператор delete, ваша программа может сначала заполнить этот буфер нулями или другими бессмысленными символами, а потом освободить эту память. Следующая программа MYDELETE.CPP перегружает оператор delete. Она сначала перезаписывает 100 байт, на которые указывает указатель, а затем освобождает память, используя для этого функцию библиотеки этапа выполнения free: #include < iostream.h> #include < stdlib.h> #include < string.h> static void operator delete(void *pointer) { void main(void) { При запуске программа выделяет память для строкового массива с помощью оператора new. Затем она копирует секреты компании в эту строку. В дальнейшем программа использует перегруженный операторdelete для освобождения памяти. Внутри функции delete приведенный ниже оператор присваивает значение переменной pointer указателю на символьную строку: char *data = (char *) pointer; Символы (char *), которые называются оператором приведения типов, предназначены только для того, чтобы сообщить компилятору C++, что функция знает, что она присваивает указатель типа void (см. выше параметры функции) указателю типа char. Если вы опустите оператор приведения типов, программа не откомпилируется. Затем функция копирует нули в 100 байт буфера и освобождает память, используя для этого функцию библиотеки этапа выполнения free. Очень важно отметить, что эта функция (оператор delete) работает только с областью памяти размером 100 байт. Поскольку данная программа выделяет память только один раз, она работает корректно. Если вы измените программу таким образом, чтобы выделялось только десять байт памяти и не сделаете подобных изменений в этой функции, то она перезапишет 90 байт памяти, которые ваша программа, возможно, использовала для других целей, приведя к ошибке. Однако, используя функции библиотеки этапа выполнения, ваши программы могут получить больше информации о размере области памяти, на которую указывает определенный указатель. Подобным образом следующая программа NEW_OVER.CPP перегружает оператор C++ new. В данном случае перегруженная функция помещает символьную строку «Учимся программировать на языке C++! » в начало выделяемой памяти: #include < iostream.h> #include < alloc.h> #include < string.h> static void *operator new(size_t size) { void main(void) { Как видите, функция new использует для выделения памяти функциюmalloc библиотеки этапа выполнения. Если размер выделяемой памяти достаточен для хранения строки «Учимся программировать на языке C++! », данная функция использует функцию strcpy библиотеки этапа выполнения для копирования строки в область памяти. ЧТО ВАМ НЕОБХОДИМО ЗНАТЬ По мере того как ваши программы становятся более сложными, вы будете выделять память в процессе выполнения, используя оператор new. Из этого урока вы узнали, как изменить поведение оператора new, сначала определяя функцию-обработчик, которую вызывает ваша программа, еслиnew не может удовлетворить запрос на память, а затем с помощью перегрузки самого оператора new. Из урока 33 вы узнаете новые способы использования входного потока cm и выходного потока соut для усовершенствования возможностей ввода и вывода ваших программ. Прежде чем перейти к уроку 33, убедитесь, что вы изучили следующее: 1. Если оператор new не может удовлетворить запрос на память, то по умолчанию он присваивает значение NULL соответствующему указателю. 2. Если вашим программам необходима другая обработка в том случае, когда new не может удовлетворить запрос на память, ваши программы могут определить свои собственные обработчики. Используя функцию set_new_handler, программа может заставить new вызвать вашу функцию, если невозможно удовлетворить запрос на память. 3. C++ позволяет вашим программам перегружать операторы newи delete. Однако, прежде чем это сделать, вы должны иметь четкое представление о свободной памяти (куче) и функциях библиотеки этапа выполнения, которые ею манипулируют. На всем протяжении этой книги вы использовали выходной поток cout для вывода информации на экран дисплея. Аналогично, многие из ваших программ использовали входной поток cin для чтения информации с клавиатуры. Оказывается, cin и cout представляют собой классовые объекты, определяемые и создаваемые с помощью заголовочного файлаiostream.h. Как объекты cin и cout поддерживают различные операторы и операции. Из данного урока вы узнаете, как расширить возможности ввода и вывода, используя функции, встроенные в классы cin и cout. К концу этого урока вы освоите следующие основные концепции:
Почти любая создаваемая вами на C++ программа будет использовать cout или cin для выполнения операций В/В (ввода/вывода). Выберите время для экспериментов с программами из этого урока. ЧТО ВНУТРИ iostream.h Начиная с урока 1, каждая написанная вами на C++ программа включала заголовочный файл iostream.h. Этот файл содержит определения, позволяющие вашим программам использовать cout для выполнения вывода и cinдля выполнения ввода. Более точно, этот файл определяет классы istream и ostream (входной поток и выходной поток), a cin и соut являются переменными (объектами) этих классов. Выберите время, чтобы напечатать файлiostream.h. Он находится в подкаталоге INCLUDE. Определения в этом файле достаточно сложны. Однако если вы пройдете по файлу медленно, то обнаружите, что большинство определений являются просто определениями классов и констант. Внутри файла вы найдете объявления переменных cin и cout. ИСПОЛЬЗОВАНИЕ cout Как вы уже знаете, cout представляет собой класс, который содержит несколько разных методов. Следующие программы иллюстрируют использование некоторых методов, которые ваши программы могут применять для форматирования вывода. Из урока 3 вы узнали, что манипулятор setw позволяет вашим программам указать минимальное количество символов, которое может занять следующее выходное значение: #include < iostream.h> #include < iomanip.h> void main(void) { cout < < «Мое любимое число» < < setw(3) < < 1001 < < endl; cout < < «Мое любимое число» < < setw (4) < < 1001 < < endl; cout < < «Мое любимое число» < < setw (5) < < 1001 < < endl; cout < < «Мое любимое число» < < setw(6) < < 1001 < < endl; } Подобным образом метод cout.width позволяет вам указать минимальное количество символов, которое будет использовать сои/для вывода следующего значения. Следующая программа COUTWIDT.CPP использует функцию cout.width для выполнения работы, аналогичной той, которую выполняет setw, что и показано ниже: #include < iostream.h> #include < iomanip.h> void main (void) { int i; for (i = 3; i < 7; i++) { cout < < «Мое любимое число»; cout. width (i); cout < < 1001 < < endl; } } Если вы откомпилируете и запустите вашу программу, на экране дисплеяпоявится следующий вывод: С: \> COUTWIDT < ENTER> Мое любимое число1001 Мое любимое число 1001 Мое любимое число 1001 Мое любимое число 1001 Подобно манипулятору setw, ширина, выбираемая с помощью функцииcout.width, действует только для следующего выходного значения. Использование символа-заполнителя Если вы используете манипулятор setw или функцию cout.width дляуправления шириной вывода, cout будет помещать пробелы до (или после для выровненных влево) значений, как это и требуется. В зависимости от назначения вашей программы вы, возможно, захотите использовать символ, отличный от пробела. Предположим, например, что вашапрограмма создает такую таблицу: Таблица информации Профиль компании………………………………………… 10 Доходы и убытки компании……………………………..11 Члены правления компании…………………………….13 В данном случае вывод предваряет номера страниц точками. Функцияcout.fill позволяет вам указать символ, который cout будет использовать для заполнения пустого пространства. Следующая программа COUTFILL.CPP создает таблицу, подобную приведенной выше: #include < iostream.h> #include < iomanip.h> void main(void) { cout < < «Таблица информации» < < endl; cout.fill (‘. ‘); cout < < «Профиль компании» < < setw(20) < < 10 < < endl; cout < < «Доходы и убытки компании» < < setw(12) < < 11 < < endl; cout < < «Члены правления компании» < < setw(14) < < 13 < < endl; } Если вы однажды выбрали символ-заполнитель с помощью cout.fill, он будет оставаться действительным, пока вы не измените его повторным вызовом cout.fill. Управление цифрами значений с плавающей точкой Если вы используете cout для вывода значения с плавающей точкой, то обычно не можете сделать каких-либо предположений о том, сколько цифр будет выводить cout no умолчанию. Однако, используя манипуляторsetprecision, вы можете указать количество требуемых цифр- Следующая программа SETPREC.CPP использует манипулятор setprecision для управления количеством цифр, которые появятся справа от десятичной точки: #include < iostream.h> #include < iomanip.h> void main(void) { float value = 1.23456; int i; for (i = 1; i < 6; i++) cout < < setprecision(i) < < value < < endl; } Когда вы откомпилируете и запустите эту программу, на экране дисплея появится следующий вывод: С: \> SETPREC < ENTER> 1.2 1.23 1.235 1.2346 1.23456 Если вы используете манипулятор setprecision для изменения точности, ваша установка действует до тех пор, пока программа повторно не использует setprecision. ВЫВОД И ВВОД ОДНОГО СИМВОЛА ЗА ОДИН РАЗ В зависимости от назначения вашей программы вам, возможно, потребуется выводить символы на дисплей или читать с клавиатуры по одному символу за один раз. Для вывода одного символа за один раз ваши программы могут использовать функцию cout.put. Следующая программа COUTPUT.CPP использует эту функцию для вывода на экран сообщенияУчимся программировать на языке C++! по одному символу за раз: #include < iostream.h> void main(void) { char string[] = «Учимся программировать на языке C++! »; int i; for (i = 0; string; i++) cout.put(string); } Библиотека этапа выполнения предоставляет функцию с именем toupper, которая возвращает заглавный эквивалент строчной буквы. Следующая программа COUTUPPR.CPP использует функцию toupper для преобразования символа в верхний регистр, а затем выводит эту букву с помощью cout.put. #include < iostream.h> #include < ctype.h> // прототип toupper void main(void) { char string[] = «C++ language»; int i; for (i = 0; string; i++) cout.put(toupper(string)); cout < < endl < < «Результирующая строка: » < < string < < endl; } Если вы откомпилируете и запустите эту программу, на экране дисплея появится следующий вывод*: С: \> COUTUPPR < ENTER> C++ LANGUAGE Результирующая строка: C++ language * К сожалению, функция toupper применима только к английским буквам. Прим. перев. ЧТЕНИЕ ВВОДА С КЛАВИАТУРЫ ПО ОДНОМУ СИМВОЛУ ЗА РАЗ Точно так же, как cout предоставляет функцию cout.put для вывода символа, cin предоставляет функцию cin.get, которая позволяет вам читать один символ данных. Чтобы воспользоваться функцией cin.get, вы просто присваиваете переменной возвращаемый этой функцией символ, как показано ниже: letter = cin.get(); Следующая программа CIN_GET.CPP выводит сообщение, в ответ на которое вам необходимо ввести Y или N. Затем она повторяет в цикле вызов cin.get для чтения символов, пока не получит Y или N: #include < iostream.h> #include < ctype.h> void main(void) { char letter; cout < < «Хотите продолжать? (Y/N): «; do { letter = cin.get(); // Преобразовать к верхнему регистру letter = toupper(letter); } while ((letter! = ‘Y’) & & (letter! = ‘N’)); cout < < endl < < «Вы ввели » < < letter < < endl; } ЧТЕНИЕ С КЛАВИАТУРЫ ЦЕЛОЙ СТРОКИ Как вы уже знаете, при использовании cin для выполнения ввода с клавиатуры, cin использует пустые символы, такие как пробел, табуляция или возврат каретки, для определения, где заканчивается одно значение и начинается другое. Во многих случаях вы захотите, чтобы ваши программы считывали целую строку данных в символьную строку. Для этого программы могут использовать функцию cin.getline. Для использованияcin.getline вам необходимо указать символьную строку, в которую будут помещаться символы, а также размер строки, как показано ниже: cin.getline(string, 64); Когда cin.get читает символы с клавиатуры, она не будет читать символов больше, чем может вместить строка. Удобным способом определить размер массива является использование оператора C++ sizeof, как показано ниже: сin.getline(string, sizeof(string)); Если позже вы измените размер массива, то вам не нужно будет искать и изменять каждый оператор с cin.get, встречающийся в вашей программе. Вместо этого оператор sizeof ‘ будет использовать корректный размер массива. Следующая программа GETLINE.CPP использует функциюcin.getline для чтения с клавиатуры строки текста: #include < iostream.h> void main(void) { char string[128]; cout < < «Введите строку текста и нажмите Enter» < < endl; cin.getline(string, sizeof(string)); cout < < «Вы ввели: » < < string < < endl; } Когда вы читаете символы с клавиатуры, то, возможно, вам понадобится читать символы вплоть до и включая определенный символ. Когда такой символ будет прочитан, возможно, вы захотите завершить операцию ввода. Для выполнения подобной операции ваша программа может передать искомый символ в cin.getline. Например, следующий вызов заставляет функцию cin.getline читать строку текста, пока не встретится возврат каретки, или пока не будут прочитаны 64 символа, или пока не встретится буква Я: cin.getline(string, 64, ‘Я’); Следующая программа UNTIL_Z.CPP использует cin.getline для чтения строки текста или символов вплоть до появления буквы Я (включая и эту букву): #include < iostream.h> void main(void) { char string[128]; cout < < «Введите строку текста и нажмите Enter» < < endl; cin.getline(string, sizeof(string), ‘Я’); cout < < «Вы ввели: » < < string < < endl; } Откомпилируйте и запустите эту программу. Экспериментируйте с различными строками текста. Некоторые из них начинайте с буквы Я, некоторые заканчивайте буквой Я, а некоторые пусть вообще не содержат букву Я. ЧТО ВАМ НЕОБХОДИМО ЗНАТЬ Каждая созданная вами на C++ программа будет, вероятно, использоватьcin или cout для выполнения операций ввода и вывода. Этот урок посвящен некоторым манипуляторам В/В и функциям, которые вы можете использовать с потоками cin и cout. По мере усложнения ваших программ они часто будут сохранять информацию в файлах. Из урока 34 вы узнаете, как в C++ выполнять операции файлового ввода и вывода. Прежде чем приступить к изучению урока 34, убедитесь, что вы освоили следующие основные концепции: 1. cin и cout являются объектами (переменными) классов i streamи ostream, которые определены в заголовочном файлеiostream.h. А если так, они предоставляют функции, которые ваши программы могут вызывать для решения определенных задач. 2. Функция cout.width позволяет вашим программам указать минимальное количество символов, которые будет использовать следующее выходное значение. 3. Функция cout. fill позволяет вашим программам указать символ, который cout будет использовать для заполнения пустого пространства устанавливаемого с помощью cout.widthили setw. 4. Манипулятор setprecision позволяет вашим программам управлять количеством цифр, выводимых справа от десятичной точки для значений с плавающей точкой. 5. Функции cin.get и cout.put позволяют вашим программам вводить или выводить один символ. 6. Функция cin.getline позволяет вашим программам читать строку текста с клавиатуры. По мере усложнения ваших программ они будут сохранять и получать информацию, используя файлы. Если вы знакомы с файловыми манипуляциями в языке С, вы сможете использовать подобные методы и в C++. Кроме того, как вы узнаете из этого урока, C++ предоставляет набор классов файловых потоков, с помощью которых можно очень легко выполнять операции ввода и вывода (В/В) с файлами. К концу данного урока вы освоите следующие основные концепции:
Многие программы, которые вы создадите в будущем, будут интенсивно использовать файлы. Выберите время для экспериментов с программами, представленными в данном уроке. И вы обнаружите, что в C++ выполнять файловые операции очень просто. ВЫВОД В ФАЙЛОВЫЙ ПОТОК Из урока 33 вы узнали, что cout представляет собой объект типа ostream(выходной поток). Используя класс ostream, ваши программы могут выполнять вывод в cout с использованием оператора вставки или различных методов класса, например cout.put. Заголовочный файлiostream.h определяет выходной поток cout. Аналогично, заголовочный файл f stream.h определяет класс выходного файлового потока с именемofstream. Используя объекты класса ofstream, ваши программы могут выполнять вывод в файл. Для начала вы должны объявить объект типаofstream, указав имя требуемого выходного файла как символьную строку, что показано ниже: ofstream file_object(«FILENAME.EXT»); Если вы указываете имя файла при объявлении объекта типа ofstream, C++ создаст новый файл на вашем диске, используя указанное имя, или перезапишет файл с таким же именем, если он уже существует на вашем диске Следующая программа OUT_FILE.CPP создает объект типа ofstreamи затем использует оператор вставки для вывода нескольких строк текста в файл BOOKINFO.DAT: #include < fstream.h> void main(void) { В данном случае программа открывает файл BOOKINFO.DAT и затем записывает три строки в файл, используя оператор вставки. Откомпилируйте и запустите эту программу. Если вы работаете в среде MS-DOS, можете использовать команду TYPE для вывода содержимого этого файла на экран: С: \> TYPE BOOKINFO.DAT < ENTER> Учимся программировать на языке C++, Вторая редакция Jamsa Press $22.95 Как видите, в C++ достаточно просто выполнить операцию вывода в файл. Популярное:
|
Последнее изменение этой страницы: 2016-05-30; Просмотров: 622; Нарушение авторского права страницы