Борис Пахомов Санкт Петербург бхв петербург 2013 удк 004. 4 Ббк 32. 973. 26018. 2 П
Скачать 17.38 Mb.
|
и элементы данных До настоящего момента каждый создаваемый нами объект имел свой собственный набор элементов данных. В зависимости от назначения вашего приложения могут быть ситуации, когда объекты одного итого же класса должны совместно использовать один или несколько элементов данных. Например, предположим, что выпишете программу платежей, которая отслеживает рабочее время для 1000 служащих. Для определения налоговой ставки программа должна знать условия, в которых работает каждый служащий. Пусть для этого используется переменная класса Однако, если все служащие работают в одинаковых условиях, ваша программа могла бы совместно использовать этот элемент данных для всех объектов типа для всех служащих).Таким образом ваша программа уменьшает необходимое количество памяти, выбрасывая 999 копий одинаковой информации. Для совместного использования элемента класса вы должны объявить этот элемент как статический. Глава 8. Классы в С. Объектно - ориентированное программирование C++ позволяет иметь объекты одного итого же типа, которые совместно используют один или несколько элементов класса. Если ваша программа присваивает значение совместно используемому элементу, то все объекты этого класса сразу же получают доступ к этому новому значению. Итак, для создания совместно используемого элемента данных класса необходимо предварять имя элемента класса ключевым словом После того как программа объявила элемент класса как она должна объявить глобальную переменную (вне определения класса, которая соответствует этому совместно используемому элементу класса. Программы могут использовать ключевое слово чтобы сделать метод класса вызываемым в то время, как программа, возможно, еще не объявила каких-либо объектов данного класса (статический метод могут вызывать только другие статические методы. Пример private: static int shared_value; Элемент shared_value некоего класса будет совместно использоваться. После объявления класса необходимо объявить элемент как глобальную переменную вне данного класса, как показано ниже int class_name::shared_value; Пример программы по совместному использованию элемента данных в разных объектах показан в листинге 8.6. Листинг 8.6 //8.5_2011.cpp #include "stdafx.h" #include #include #include { public: book_series(char *, char *, float); void show_book(void); void set_pages(int); private: static int page_count; это будет общий элемент char title[64]; char author[ 64 ]; 160 Часть I. Изучение языка С/С++ float price; }; int book_series::page_count; объявление глобальной переменной вне класса void book_series::set_pages(int pages) { page_count = pages; } book_series::book_series(char *title, char *author, float price) Конструктор класса { strcpy(book_series::title, title); т. к. используется strcpy(), надо подключать класс string*/ strcpy(book_series::author, author); book_series::price = price; } void book_series:: show_book (void) { printf("Title: %s\n",title); printf("Author:%s\n",author); printf("Price: %.2f\n",price); printf("Pages: %d\n",page_count); } void main() { book_series programming("Studiing C++", "Author1", 22.95); создаем объект programming с помощью конструктора book_series word( "Studiing to work with Word for Windows 7", "Author2", 19.95); создаем объект word с помощью конструктора word.set_pages(256); задаем кол-во страниц в объекте word. Оно должно отразиться в объекте programming*/ programming.show_book (); word.show_book() ; programming.set_pages(512); изменили page_count programming.show_book(); вывод на экран данных объекта //programming word.show_book(); вывод на экран данных объекта //word _getch(); } Результат работы программы приведен на рис. 8.6. Как видите, класс объявляет page_count как static Сразу же за определением класса программа объявляет элемент page_count как глобальную переменную. Глава 8. Классы в С. Объектно - ориентированное программирование Рис 8.6. Работа со статическими элементами данных в классе Когда программа изменяет элемент изменение сразу же проявляется во всех объектах класса ввели новое количество 512 водном объекте, такое же количество появилось ив другом объекте. Использование элементов с атрибутами public static, если объекты не существуют Как мы только что узнали, при объявлении элемента класса как static этот элемент совместно используется всеми объектами данного класса. Однако возможны ситуации, когда программа еще не создала объектно ей необходимо использовать некий элемент. Для использования элемента программа должна объявить его как public и static . Например, следующая программа (листинг 8.7) использует элемент page_count из класса даже если объекты этого класса не существуют. Листинг 8.7 //8.7_2011.cpp #include "stdafx.h" #include #include { book_series(); 162 Часть I. Изучение языка С/С++ public: static void show_book(void); для вывода статического элемента у функции д.б. такой же атрибут static int page_count; private: char title [64]; char author[64]; float price; }; int book_series::page_count; Объявление переменной как глобальной, тку нее атрибут static void book_series::show_book (void) { printf("page_count=%d\n",page_count); } void main(void) { book_series::page_count = 256; идет присвоение значения 256 переменной //employee worker("Happy Jamsa", 101, 10101.0); // book_series B(); создаем объект, чтобы вывести элемент через функцию Show(). Но программа работает и без объекта book_series::show_book(); _getch(); } Результат работы программы показан на рис. 8.7. Рис 8.7. Работа с элементом класса, когда объект класса еще не создан В данном случае, поскольку класс определяет элемент класса page_count как программа может обратиться к этому элементу класса, даже если объекты класса book_series не существуют. Предыдущая программа иллюстрировала использование статических элементов данных. Подобным образом C++ позволяет определить статические функции- элементы (методы. Если вы создаете статический метод, ваша программа может вызывать такой метод, даже если объекты небыли созданы. Этот факт и был про Глава 8. Классы в С. Объектно - ориентированное программирование демонстрирован предыдущей программой:сначала в программе был создан объект В. Программа отработала только тогда, когда методу вывода на экран был присвоен атрибут Затем строка, в которой был объявлен объект, была за- комментирована. Программа прошла компиляцию и при выполнении показала тот же результат. Частные и общие данные. Интерфейсные функции При определении класса мы видели, что в нем задаются секции public и которые разграничивают доступ к данным класса. То есть атрибуты public и private управляют доступом к элементам класса со стороны основной программы ( main() ). В частности, программа может обратиться к общим ( public ) элементам с помощью конструкции имя объекта.имя члена класса. Такая конструкция не поможет достать данные из секции private в соответствии с определением секции. Поэтому программа может обращаться к частным ( private ) элементам только с использованием функций данного класса. То есть, вместо того чтобы, например, присвоить какому-то элементу из этой секции класса некоторое значение, программа должна вызвать метод класса. Такие методы называются интерфейсными функциями. Предотвращая сих помощью прямой доступ к элементам данных, "спрятанных" в секции private , вы таким образом можете гарантировать, что данным класса всегда будут присваиваться допустимые значения. Интерфейсную функцию всегда надо помещать в секцию public класса, чтобы к ней был доступ и чтобы с ее помощью получать доступ к данным из секции Использование оператора глобального разрешения для элементов класса Чтобы избежать конфликта между именами параметров методов класса и именами элементов класса, применяют так называемый оператор глобального разрешения для элементов класса, который обозначается двумя двоеточиями подряд ( :: ). Если перед именами элементов класса ставить имя класса, к которому принадлежит элемента за именем — оператор глобального разрешения, то конфликтов между именами можно избежать. Например, выражение employee::employee_id = employee_id; показывает, что идентификатор слева от знака равенства — элемент класса employee , а справа — классу employee не принадлежит. 164 Часть I. Изучение языка С/С++ ГЛАВА Вводи вывод в языках Си С++ Ввод и вывод в С Ввод/вывод в языке С осуществляется функциями из стандартных библиотек. Чтобы ими пользоваться, в программу надо включать соответствующие файлы stdio.h, stdlib.h, и др. Главная библиотека — stdio.h. В ней содержатся основные функции ввода/вывода, в том числе и обеспечивающие стандартный ввод/вывод. Ввод/вывод файлов Чтобы работать с файлом, его сначала следует открыть связать со специальной структурой с именем FILE , которая описана в библиотеке stdio.h ив которой задаются характеристики файла (размер буфера ввода/вывода, состояние файла, последняя прочитанная запись и т. п. Связь эта выполняется с помощью функции fopen() , которая тоже входит в библиотеку stdio.h и возвращает указатель на структуру. Поэтому в программе прежде всего следует задать указатель на структуру (например, FILE *fp; ), а затем записать оператор собственно открытия файла имя файла, способ открытия файла); Функция открытия имеет два параметра имя открываемого файла и способ открытия файла. Способ открытия файла определяет, как будет пользователь работать с файлом читать его, писать в него или делать что-то еще. Рассмотрим способы открытия файла. Их коды и значения приведены ниже r — файл открывается только для чтения из него w — файл открывается только для записи в него (если файл не существует, он создается a — файл открывается для дозаписи информации вконец файла. Если файл не существует, он создается для записи в него r+ — существующий файл открывается для обновления чтения и записи 166 Часть I. Изучение языка С/С++ w+ — создается новый файл для работы в режиме обновления такой файл можно будет и читать, и записывать в него a+ — файл открывается для дозаписи информации вконец файла. Если файл не существует, он создается. Если существует, то открывается для дозаписи вконец файла. Если по какой-либо причине открытия файла не произошло (например, задано имя несуществующего файла, то функция fopen() возвращает значение NULL . Поэтому открытие файла следует осуществлять так if((fp=fopen(name,mode)) == NULL) операторы обработки ошибки открытия} остальные операторы программы После того как программа сданным файлом отработала, следует "отвязать" структуру от отработавшего файла или, как говорят, закрыть файл. Это осуществляет функция fclose(fp) . Она не только разрывает связь структуры с файлом, но и записывает в память оставшееся содержимое буфера ввода/вывода, через который собственно и организуется ввод/вывод. Только после закрытия файла с ним можно выполнять какие-либо действия, т. кон "свободен, "не привязан. Например, его можно удалить или заново открыть в другом режиме открытия и т. д. Основные функции для работы с файлами После того как файл открыт, для чтения или записи используют специальные функции. Приведем перечень функций для работы с файлами. Функция Формат fputc(c, Выводит символ в файл (с — выводимый символ, fp — указатель файла. Функция Формат Выводит строку в файл ( s — выводимая строка, fp — указатель файла. Функция Формат Читает один символ из файла с указателем fp . Переменная c описана как char В случае ошибки или достижения конца файла возвращает Функция Формат fgets(s,maxline,fp); Глава 9. Вводи вывод в языках Си С Читает строку в s ( s — массив символов или указатель типа char (предварительно должна быть выделена память для чтения с использованием указателя, maxline — максимальное число символов, которое требуется читать из файла с указателем fp ). В случае ошибки или достижения конца файла возвращает Функция Формат fread(buf, m, n, Читает из файла c указателем fp n элементов данных, каждый из которых имеет длину m байтов. Чтение происходит в буфер, на который указывает указатель например, char buf[50] или char *buf (нов этом случае надо выделить память для буфера. Общее количество байтов чтения составит n m . Функция возвращает количество прочитанных элементов, а по достижении конца файла или возникновении ошибки чтения возвращает Функция Формат fwrite(const void ptr, m, n, Пишет в файл с указателем fp : добавляет n элементов в выходной файл, каждый элемент длиной в m байтов. Данные записываются из буфера, на который указывает указатель ptr (этот указатель указывает на некоторый объект, например, на структуру. Общее число записанных байтов равно n m . В случае ошибки записи функция возвращает ноль, в противном случае — количество записанных элементов. Функция Формат Устанавливает указатель в файле в позицию, отстоящую на n байтов от текущей, а направление перемещения (вперед или назад) задается параметром m , который может быть одним из значений 0, 1, 2 или одной из трех символических констант, определенных в файле stdio.h: SEEK_SET 0 — к началу файла SEEK_CUR 1 — указатель в текущей позиции файла SEEK_END 2 — к концу файла. Функция используется для ввода/вывода потоком. Для работы нес потоковыми данными следует использовать функцию После функции fseek() можно выполнять операции обновления в файлах, открытых для обновления. При удачном завершении работы fseek() возвращает ноль, в противном случае — иное значение. Функция возвращает код 168 Часть I. Изучение языка С/С++ ошибки, только если файл или устройство не открыты. В этих случаях глобальная переменная errno принимает одно из следующих значений EBADF — неверный указатель файла EINVAL — неверный аргумент функции ESPIPE — поиск на устройстве запрещен. Функция Формат long int Возвращает текущее значение указателя файла fp (те. номер текущей позиции) в виде значения типа long int . Отсчет идет в байтах от начала файла. Возвращаемое значение может быть использовано в функции fseek() . Если обнаружены ошибки, функция возвращает значение -1L и присваивает глобальной переменной положительное значение. Функция Формат Вводит данные из файла c указателем fp , преобразует их по форматам, записанным в управляющей строке Conrtol , и отформатированные данные записывает в аргументы arg1,...,argn . Подробные сведения о работе этой функции можно получить, ознакомившись с работой функции scanf() (функцию scanf() мы рассмотрим в разд. "Функции стандартного ввода/вывода" далее в этой главе. Функция Формат Выводит данные в файл c указателем fp , преобразует аргументы arg1,...,argn к форматам, которые записаны в управляющей строке Conrtol , и отформатированные данные записывает в файл. Подробные сведения о работе этой функции можно получить, ознакомившись с работой функции printf() (об этой функции см. разд. "Функции стандартного ввода/вывода" далее в этой главе. Функция Формат Устанавливает указатель позиционирования в файле с указателем fp на начало потока. Функция rewind(fp) эквивалентна функции fseek(fp, 0L, SEEK_SET) за исключением того, что rewind() сбрасывает индикатор конца файла и индикаторы ошибок, а сбрасывает только индикатор конца файла. После функции rewind() можно выполнять операции обновления для файлов, открытых для обновления. Возвращаемого значения нет. Глава 9. Вводи вывод в языках Си С Функция Формат Функция тестирует поток на ошибки чтения/записи. Если индикатор ошибки устанавливается, то он остается в таком положении, пока не будут вызваны функции clearerr() или rewind() , или до того момента, пока поток не закроется. Если в файле была обнаружена ошибка, то функция ferror() возвращает ненулевое значение. Функция Формат FILE *freopen(const char *FILEname, const char *mode, FILE Функция подставляет файл, заданный в первом параметре, вместо уже открытого потока. Она закрывает поток независимо оттого, открыт ли он. Эта функция полезна для замены файла, связанного со стандартными устройствами ввода/вывода: stdin , stdout или stderr . Способы открытия файла аналогичны таким же в функции fopen() . При успешном завершении функция возвращает указатель типа FILE (как и функция fopen() ), при неудачном — Пример перенаправления потока с помощью функции приведен в листинге 9.1. Листинг 9.1 /* перенаправление стандартного вывода в файл */ if (freopen("OUTPUT.FIL", "w", stdout) == NULL) fprintf(stderr, "error redirecting stdout\n"); /* этот вывод пойдет уже в файл */ printf("This will go into a FILE."); /* закрытие стандартного потока fclose(stdout); Функция Формат Обнаруживает конец файла с указателем fp : тестирует поток на возникновение индикатора конца файла (который наступает после прочтения последней записи. Как только индикатор установлен, операции чтения файла возвращают индикатор до тех пор, пока не выполнена функция rewind() — "перемотка" в начало файла или пока файл не будет закрыт. Индикатор конца файла переустанав- ливается с каждой операцией ввода. Функция возвращает ненулевую величину, 170 Часть I. Изучение языка С/С++ если индикатор конца файла был обнаружен при последней операции чтения, в противном случае — ноль. Функция Формат Здесь fp — указатель файла ( FILE *fp; ). Функция выдает ненулевое значение, если операция с файловым потоком завершается с ошибкой (например, возникает ошибка чтения файла. Для обработки ошибок ввода/вывода следует записать эту функцию перед блоком работы с файлом в виде команды обработки ошибок ввода/вывода} Как только произойдет ошибка, выполнится эта функция, и начнут работать команды обработки ошибок. Функция Формат exit(int Эта функция используется для срочного завершения работы программы при обработке ошибок открытия файла (и не только для этого, а для прерывания работы программы по каким-либо другим причинам. Но перед завершением все файлы закрываются, остатки данных, находящиеся в буфере вывода, записываются в память и вызываются функции обработки ошибок, предварительно зарегистрированные специальной функцией atexit() . Эти функции обработки ошибок надо самому написать и зарегистрировать их с помощью вызова функции Для вызова функции atexit() требуется выполнить команду Каждый вызов atexit() регистрирует новую функцию exit() . Можно зарегистрировать до 32 функций exit() . Они будут выполняться по принципу работы стековой памяти "последний вошел — первый вышел" (те. последняя зарегистрированная функция будет выполнена первой. Поясним сказанное на примере программы, приведенной в листинге 9.2 (результат работы программы показан на рис. 9.1). Листинг 9.2 // 9.1_2011.cpp #include "stdafx.h" #include #include #include Глава 9. Вводи вывод в языках Си С это первая функция exit() */ void exit_fn1(void) { printf("Exit function #1 called\n"); _getch(); } это вторая функция exit() */ void exit_fn2(void) { printf("Exit function #2 called\n"); _getch(); } Это основная программа, в которой происходит регистрация заданных вами функций exit(). Здесь же применяется и сама функция exit(), которая перед завершением работы программы станет вызывать зарегистрированные функции, определенные выше */ int main(void) { /* регистрация функции #1 */ atexit(exit_fn1); /* регистрация функции #2 */ atexit(exit_fn2); /*exit() сначала вызовет функцию #2, т. кона была зарегистрирована последней, а затем — функцию #1. После этого программа завершится printf("fn2 will be called first\n"); exit(0); _getch(); здесь задержки экрана не получится, т. к. exit() закрывает программу } Рис 9.1. Результат работы программы листинга Какое бы числовое значение вы не подставили вместо аргумента функции, вызов зарегистрированных функций exit() все равно произойдет. Если жене зарегистрирована ни одна функция, то произойдет завершение программы. Регистрация функций) действительна только в пределах одной программы. 172 Часть I. Изучение языка С/С++ |