Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Бинарные и типизированные фаилы.Общие черты и отличия.Представления данных в них.






Текстовые и двоичные файлы(типизированные и бинарные)

Текстовые файлы, с которыми мы имели дело до сих пор, отличаются двумя свойствами:

1.файлы делятся на строки, и конец строки отмечается специальным символом «new line» (новая строка), роль которого в системе ввода/вывода С++ играет ‘\n’;

2.при вводе чисел выполняется преобразование из символьного вида во внутренний формат (вспомните функцию atoi — см. листинг 3.12); при выводе чисел — из внутреннего формата в символьный;

Двоичные файлы, как вы понимаете, этими свойствами не обладают. Это означает, что двоичные файлы на строки не делятся, и при вводе/выводе никаких преобразований не делается. При операции записи в двоичный файл попадает ровно столько байтов, сколько записываемый объект занимает в памяти. Например, целое число, записанное в двоичный файл, займет на диске sizeof(int) байтов. Это существенно отличается от записи в текстовый файл, где количество записываемых по умолчанию символов зависит от величины числа. Например, число 1 в текстовом файле займет 1 байт, а 55555 — 5 байтов. Примерами двоичных файлов могут служить файлы выполняемых программ (с расширением exe). Чтобы прочувствовать разницу, давайте напишем программу, которая генерируют 1000 целых случайных чисел и выводит их в файлы. Один файл будет текстовым, а другой — двоичным.

Тут нас поджидает одна проблема: в классах fstream, ifstream, ofstream отсутствуют методы ввода/вывода целых чисел в файл. Однако нам нет необходимости писать собственные функции, если мы умеем работать с указателями. Первый параметр методов read/write — это char *. Поэтому мы можем непосредственно обращаться к этим методам, используя подходящее преобразование указателей. Посмотрите, как это делается для типа long; from — входной поток, to — выходной поток (листинг 6.15).

//Листинг 6.15. Ввод/вывод встроенных типов данных

long a;

from.read((char *)& a, sizeof(long));

to.write((char *)& a, sizeof(long));

Преобразование типов можно делать и в стиле С++:

to.write(reinterpret_cast< char *> (& a), sizeof(long));

from.read(reinterpret_cast< char *> (& a), sizeof(long));

20.Пользовательские типы данных.Структуры.Массивы структур/записей.

К пользовательским типам данных относятся нестандартные данные, о структуре которых система не имеет представления, и операции над которыми стандартом языка C не определены. Структура таких данных становится известной компилятору только по описанию, содержащемуся в тексте исходной программы. К пользовательским данным такого типа относятся массивы (о них речь шла в предыдущем разделе), структуры (в других алгоритмических языках они известны под термином записи), перечисления (в некоторых книгах по языкам C, C++ их относят к целочисленным данным) и объединения.

9.1. Структуры

Первоначальным образом для данных типа структур явились строки таблиц, с которыми знаком любой человек. Характерным для таблиц любого содержания является наличие столбцов, в каждом из которых хранятся однотипные данные. Однако в соседних столбцах типы данных могут отличаться. Если специфической особенностью массивов является использование одного и того же типа для всех элементов массива, то строки таблиц можно представлять как последовательность полей данных разного типа. Для каждого поля строки таблицы известно наименование соответствующего столбца таблицы и тип размещаемого в этом поле значения. Например, поле " Фамилия" заполняется текстовой информацией, поле " Год рождения" хранит целочисленные данные, на поле " Пол" достаточно записывать единственный символ 'М' или 'Ж' и т.д.

9.1.1. Объявление и инициализация структур

То, что принято называть " шапкой" таблицы в языках программирования носит название шаблона структуры. Например, шаблон структуры, описывающей данные о книге, может быть устроен следующим образом:

struct book {

char title[40]; //наименование

char authors[30]; //авторы

char publishing_house[15]; //издательство

int year; //год издания

int pages; //количество страниц

float price; //цена }

Для доступа к соответствующим полям структур используются составные имена, образованные из имени структуры и имени поля:

strcpy(b1.title, " C++: Экспресс курс");

strcpy(b1.authors, " В.Лаптев");

cout < < b1.title;

b1.year=2004;

Если мы имеем дело с указателем, который настроен на адрес структуры, то составные имена записываются с использованием двух символов " -> ":

struct book *p=& b1; //указатель на структуру

strcpy(p-> title, " C++: Экспресс курс"

strcpy(p-> authors, " В.Лаптев");

cout < < p-> title;

p-> year=2004;

Структуры могут объединяться в массивы:

struct book c[20]; //массив структур

И тогда для доступа к полям соответствующего элемента используются индексированные составные имена:

strcpy(с[2].title, " Язык C++ "

strcpy(c[2].authors, " В.В.Подбельский");

cout < < c[2].title;

c[2].year=1996;

struct book *pс=с;

strcpy(pс[2]-> title, " C++: Экспресс курс"

strcpy(pс[2]-> authors, " В.Лаптев");

cout < < pс[2]-> title;

pс[2]-> year=2004;

23.Перегрузка операций для структур: определение правил для операторов согласно разработанным пользовательским типам.

этой главе описывается аппарат, предоставляемый в C++ для перегрузки операций. Программист может определять смысл операций при их применении к объектам определенного класса. Кроме арифметических, можно определять еще и логические операции, операции сравнения, вызова () и индексирования [], а также можно переопределять присваивание и инициализацию. Можно определить явное и неявное преобразование между определяемыми пользователем и основными типами. Показано, как определить класс, объект которого не может быть никак иначе скопирован или уничтожен кроме как специальными определенными пользователем функциями.

6.1 Введение

Часто программы работают с объектами, которые являются конкретными представлениями абстрактных понятий. Например, тип данных int в C++ вместе с операциями +, -, *, / и т.д. предоставляет реализацию (ограниченную) математического понятия целых чисел. Такие понятия обычно включают в себя множество операций, которые кратко, удобно и привычно представляют основные действия над объектами. К сожалению, язык программирования может непосредственно поддерживать лишь очень малое число таких понятий. Например, такие понятия, как комплексная арифметика, матричная алгебра, логические сигналы и строки не получили прямой поддержки в C++. Классы дают средство спецификации в C++ представления неэлементарных объектов вместе с множеством действий, которые могут над этими объектами выполняться. Иногда определение того, как действуют операции на объекты классов, позволяет программисту обеспечить более общепринятую и удобную запись для манипуляции объектами классов, чем та, которую можно достичь используя лишь основную функциональную запись. Например:

class complex {

double re, im;

public:

complex(double r, double i) { re=r; im=i; }

friend complex operator+(complex, complex);

friend complex operator*(complex, complex); };

определяет простую реализацию понятия комплексного числа, в которой число представляется парой чисел с плавающей точкой двойной точности, работа с которыми осуществляется посредством операций + и * (и только). Программист задает смысл операций + и * с помощью определения функций с именами operator+ и operator*. Если, например, даны b и c типа complex, то b+c означает (по определению) operator+(b, c). Теперь есть возможность приблизить общепринятую интерпретацию комплексных выражений. Например:

void f(){

complex a = complex(1, 3.1);

complex b = complex(1.2, 2);

complex c = b;

a = b+c;

b = b+c*a;

c = a*b+complex(1, 2); }

Выполняются обычные правила приоритетов, поэтому второй оператор означает b=b+(c*a), а не b=(b+c)*a.

6.2 Функции Операции

Можно описывать функции, определяющие значения следующих операций:

 

+ - * / % ^ & | ~!

= += -= *= /= %= ^= & =

|= > > > = = & &

|| ++ -- [] () new delete

Последние четыре - это индексирование (#6.7), вызов функции (#6.8), выделение свободной памяти и освобождение свободной памяти (#3.2.6). Изменить приоритеты перечисленных операций невозможно, как невозможно изменить и синтаксис выражений. Нельзя, например, определить унарную операцию % или бинарную!. Невозможно определить новые лексические символы операций, но в тех случаях, когда множество операций недостаточно, вы можете использовать запись вызова функции. Используйте например, не **, а pow(). Эти ограничения могут показаться драконовскими, но более гибкие правила могут очень легко привести к неоднозначностям. Например, на первый взгляд определение операции **, означающей возведение в степень, может показаться очевидной и простой задачей, но подумайте еще раз. Должна ли ** связываться влево (как в Фортране) или вправо (как в Алголе)? Выражение a**p должно интерпретироваться как a*(*p) или как (a)**(p)?

Имя функции операции есть ключевое слово operator (то есть, операция), за которым следует сама операция, например, operator void f(complex a, complex b) { complex c = a + b; // сокращенная запись complex d = operator+(a, b); // явный вызов }

6.2.1 Бинарные и Унарные Операции

Бинарная операция может быть определена или как функция член, получающая один параметр, или как функция друг, получающая два параметра. Таким образом, для любой бинарной операции @ aa@bb может интерпретироваться или как aa.operator@(bb), или как operator@(aa, bb). Если определены обе, то aa@bb является ошибкой. Унарная операция, префиксная или постфиксная, может быть определена или как функция член, не получающая параметров, или как функция друг, получающая один параметр. Таким образом, для любой унарной операции @ aa@ или @aa может интерпретироваться или как aa.operator@(), или как operator@(aa). Если определена и то, и другое, то и aa@ и @aa являются ошибками. Рассмотрим следующие примеры:

class X {

// друзья

friend X operator-(X); // унарный минус

friend X operator-(X, X); // бинарный минус

friend X operator-(); // ошибка: нет операндов

friend X operator-(X, X, X); // ошибка: тернарная

// члены (с неявным первым параметром: this)

X* operator& (); // унарное & (взятие адреса)

X operator& (X); // бинарное & (операция И)

X operator& (X, X); // ошибка: тернарное

};

Когда операции ++ и -- перегружены, префиксное использование и постфиксное различить невозможно.

6.2.3 Операции и Определяемые Пользователем Типы

Функция операция должна или быть членом, или получать в качестве параметра по меньшей мере один объект класса (функциям, которые переопределяют операции new и delete, это делать необязательно). Это правило гарантирует, что пользователь не может изменить смысл никакого выражения, не включающего в себя определенного пользователем типа. В частности, невозможно определить функцию, которая действует исключительно на указатели.

Функция операция, первым параметром которой предполагается основной тип, не может быть функцией членом. Рассмотрим, например, сложение комплексной переменной aa с целым 2: aa+2, при подходящим образом описанной функции члене, может быть проинтерпретировано как aa.operator+(2), но с 2+aa это не может быть сделано, потому что нет такого класса int, для которого можно было бы определить + так, чтобы это означало 2.operator+(aa). Даже если бы такой тип был, то для того, чтобы обработать и 2+aa и aa+2, понадобилось бы две различных функции члена. Так как компилятор не знает смысла +, определенного пользователем, то не может предполагать, что он коммутативен, и интерпретировать 2+aa как aa+2. С этим примером могут легко справиться функции друзья.

Все функции операции по определению перегружены. Функция операция задает новый смысл операции в дополнение к встроенному определению, и может существовать несколько функций операций с одним и тем же именем, если в типах их параметров имеются отличия, различимые для компилятора, чтобы он мог различать их при обращении (см. #4.6.7).






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.