Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Допустимые операции над переменными типа перечисление.



Структуры.

Форматы определения структурного типа.

1) struct имя_структурного_типа{определение элементов}

2) typedef struct{определение_элементов}имя_структурного_типа

3) typedef struct имя_структурного_типа_1

{определение элементов}имя_структурного_типа_2

4) #define STUD struct{char f[10], int nz;}

При определении структурного типа память не выделяется. Для выделения памяти под структурный тип, нужно объявить объект структурного типа.

Форматы определения объектов:

1) имя_структурного_типа список_объектов;

2) struct имя_структурного_типа{определение_элементов}список_объектов;

3) struct {определение_элементов}список_объектов//когда имя не требуется

Память, выделяемая под объекты структурного типа.

Struct st

{int i;

float f;

char ch;

}s( ← имя объекта структурного типа);

   I       f       ch

|__ __|__ __ __ __|__|

2 б        4 б   1 б

sizeof(имя_структурного_типа);

sizeof(имя_объекта_структурного_типа);//можно без скобок

Операции над объектами структурного типа.

1) Разрешена инициализация.

2) Присваивание однотипных структур.//наиболее используемая из операций

Операция присваивания для объектов структурного типа в статической памяти выполняется по умолчанию, как побитовое копирование.

3) Сравнение поэлементно.

Доступ к элементам определения структурного типа.

1. С помощью операции «точка»:

имя_объекта.имя_элемента

goods tea; tea.price;

2. С помощью операции «стрелка» :

goods*tovar;

tovar → name;

Структуры, массивы и указатели.

1. В качестве элементов структуры можно использовать массив:

Struct

{double m;

float coord[3];

}point={12.3, {-1.0, 2.2, -4.3}};

point.coord[0];

2. В качестве элементов структуры можно использовать ранее определенные структуры.

struct date {int d, m, y};

struct goods{…

                           date data;}yea;

tea.data.y;

3. Массивы структур.

complex set[80]={{…}{…}{…}…{…}};( ← 80 структур)

4. Указатели на структуры, ссылки, массивы.

struct{…}point( ← имя_объекта);&pp( ← ссылка)=point, *pptr( ← указатель) =&point( ← адрес point);

point1[30];

point1 –имя указателя или константна указателя

point1[5];

pptr=point1;

pptr++;//операция инкремента

pptr--;//операция декремента

Элементы структурного типа не могут быть не определены выше структуры, но могут быть указателем на определяемую структуру.

Struct stud

{int nz;

char f[10];

stud *uk;} – это позволяет использовать динамические структуры данных для случаев когда объем данных не известен даже во время выполнения программы

Объединения (смешения).

union sm( ← имя типа объединения)

{int i;

float f;

char ch;

}U;

Доступ:

U.f

ch i f

|__ |__|__ __|

 1б 2б 4б

Тип объединения можно использовать, когда элементы используются поочерёдно. Объединения часто использовались в составе структур

Struct st

{char ch[5];

int i;

union{int a;

           float b;

           char c[7];

           }UV;

}dat;

Доступ:

dat.UV.c[5];

Тип перечисление.

Есть две формы определения переменных типа перечисление.

1. enum{список_значений}имя_переменной;

enum{kr, gel, zel}svetofor;

2. enum имя_типа_перечисления{список_значений};

имя_типа_перечисления имя_переменной;

enum typsvet{kr, gel, zel};

typsvet svetofor;

Последовательность значений автоматически нумеруется от 0 и т.д. до 255:

enum typsvet{kr=1, gel, zel};

Или значения можно задавать самому:

enum typsvet{kr=5, gel=10, zel=100};

Допустимые операции над переменными типа перечисление.

1. Можно присваивать значения константам того же типа.

svetofor=kr;

2. Разрешены операции проверки на равенство(==) и неравенство(!=).

3. Можно использовать в качестве оператора switch.

4. В качестве индексов элементов массива.

5. Выводить в качестве значений целого типа.

Классы

Это пользовательские типы данных. Причиной появления классов являются недостатки структурного типа.

Struct time                                                    class time {

{int h, m, s;                                                    public:

}                                                                                          time();                             функции

t;                                                                                        void settime(int, int, int); открытая (интерфейсная часть)                                                   класса

                                                                                           void printtime();                         возможен доступ извне

                                                                                           private:                                          

                                                                                                           int h; // 0-23

                                                                                                           int m; // 0-59 закрытая (доступ внутри класса)

                                                                                                           int s; // 0-59 };         данные-элементы

public:  (открытый) private: (закрытый)  protected: (защищенный) - спецификаторы доступа

time() – конструктор, вызывается автоматически при создании объекта класса

void settime – устанавливает новое время

void printtime – выводит время

 

Недостатки:

1. Разрешена всего одна операция – присваивание

2. Структуры не могут быть выведены как единое целое

3. Инициализация структур не обязательна, поэтому появляются объекты с неопределенными свойствами

4. Пользователь имеет прямой доступ к элементам структур, поэтому при инициализации возможна ошибка

5. Если нужно изменить реализацию структурного типа, то необходим просмотр всей программы, что требует большого времени

 

Примечание:

1. Данные элементы класса не могут получить начальные значения в теле класса, где они объявлены, получают в конструкторе и/или функциях

2. Функции элементы имеют прямой доступ к данным элементам класса, поэтому они могут не иметь параметров

3. Каждая функция элемент может быть определена в теле класса, условие – она должна быть короткой

4. Для идентификации функции используется запись <имя класса>::

5. В общем случае класс должен иметь деструктор ~ time(); - деструктор предназначен для разрушения созданного конструктором объекта, в примере деструктора нет, он создается автоматически, правильно разрушает объект, т.к. объект использует статическую память, случае динамической памяти – наличие деструктора в классе – обязательно

6. Реализацию класса можно изменять до тех пор, пока не придется изменять интерфейсную часть класса, это упрощает модификацию программы

7. В классах принято отделять объявление от реализации, размещая их в разных файлах

Примечание:

1. Переменные, объявленные в функции-элементе, известны только этой функции и имеют область действия – только эту функцию. Если имя такой переменой совпадает с именем данного элемента класса, то доступ к данному элементу класса внутри функции будет такой - <имя класса>::<имя данного элемента класса>

2. При этом доступ к закрытым данным-элементам класса принято контролировать специальными функциями – функциями доступа.

Void seth (int); - для установки часов int geth() {return h;}

 

Отделение интерфейса от реализации в классах

Для этого используют директивы:

1. #ifndef – проверка неопределенности идентификатора

2. #endif – окончание предыдущей директивы

В целом это условные директивы

3. #define – определение идентификатора или макроса

Макрос – операция обозначаемая символьными строками

#define имя_константы (идентификатор макроса) значение_константы (замещающий текст)

 

Заголовочный файл содержит только объявление класса структуры функции, исполняемых операторов в нем нет, можно включать только очень короткие функции, они имеют признак inline.

Обслуживающие функции утилиты

Обслуживающие функции утилиты - предназначены для обслуживания других функций элементов класса, нет смысла включать их в открытую часть класса, помещают в закрытую, доступ к ним через интерфейс, т.е. через открытую часть класса.

 

Конструкторы

Каждый класс по технологии должен иметь хотя бы один конструктор, если его нет, создается автоматически, класс создает объект с неопределенными, т.е. неизвестными свойствами, для задания определенных свойств необходима соответствующая функция-элемент. Рекомендуется в составе класса иметь конструктор с умолчанием, вызывается он без указания параметров, затем функция-элемент переопределяет свойства объекта.

список инициализации, если он есть, то объект создается в два этапа – первый – конструктором с умолчанием задаются нулевые параметр, затем второй этап – из списка инициализации передаются значения параметров в переопределенный конструктор, соответствующие параметры модифицируются. Наиболее верный вариант.

Динамически создаваемый объект

Как любая переменная объект класса может создаваться как статически, так и динамически, в последнем случае он будет частично или полностью находится в динамической памяти.

 

Конструктор с параметрами

Конструктор с параметрами:

с параметрами m1 инициализирует данный элемент в mem1, параметром m2 инициализирует память выделенную по указателю mem2.

 

Деструктор

По выходу из функции динамическая память остается занятой, при последующих вызовах dd будет утечка памяти, в итоге программа зависнет. Для того, чтобы динамическая память освобождалась в то же самое время, когда уничтожается объект нужен деструктор.

 

Определение деструктора

Template <class T>

Dyn <T>:: ~ dyn ()

{cout << “Деструктор:” << mem1 << ‘| << *mem2<< endl;

Delete mem2;

}

 

Деструктор, как и конструктор, вызывается автоматически.

 

Вывод: обычно деструкторы вызываются в последовательности, обратной вызову конструкторов, исключение для статических локальных объектов.

Присваивание

По умолчанию присваивание выполняется как побитовое копирование. Для переменных и объектов, находящихся в статической памяти, такое присваивание выполняется верно, для динамически - нет.

Для того, чтобы пользоваться известными знаками операций для объектов класса в такой же записи, как для стандартных типов, операции нужно перегружать, для этого используются функции – операции, отличие – имя функции-операции состоит из слова operator, а затем знак операции.

В функции создаются два локальных объекта А и В и выполняется присваивание В=А, по выходу из функции эти объекты должны разрушаться, предположим объект В разрушается первым, при разрушении объекта будет вызван деструктор который освободит динамическую память, адрес находится в mem2, следовательно память под разыменованным А будет освобождена, затем уничтожается объект А, при его разрушении будет вызван деструктор, но память уже освобождена и правильный вызов деструктора для А будет ошибочным, следовательно неправильно выполняется операция присваивания.

Стек

Last in – first out

LIFO

 

15 вершина стека
-40
37
25

 

Используются в:

1. Системном ПО

2. Компиляторах

3. При реализации рекурсивных алгоритмов

 

 

Topуказатель на вершину стека

NULL – 0

 

Для работы со стеком определены 2 функции:

1. Функция push – вталкивать (помещать в стек)

2. Pop – выталкивать (делать выборку) из стека

3. Top – указатель на вершину стека

 

Очереди

First in

First out FIFO

Используются:

1. В буферизованном вводе-выводе

2. В моделировании

3. В диспетчеризации задач операционной системы

 

Очередь приоритетов

В рассмотренной очереди все элементы имеют одинаковый приоритет. На практике обычно элементы с разными приоритетами.

Линейные списки

Двунаправленные

Кроме поля данных есть 2 поля указателей – prev (указывает на адрес предыдущего элемента) и next (следующего). Для повышения надежности список делают кольцевым.

Если все узлы списка имеют один и тот же тип, то такие списки называются однородными.

Поиск хэшированием

В любом линейном списке возможен только линейный поиск, тогда эффективность поиска О(n). Для ускорения поиска в списках преобразуют ключ узла (например, целое число) в индекс, это преобразование в хэш-функции, чаще всего используют функцию, которая находит остаток от деления

нацело.

 

Бинарные деревья

Виды деревьев:

1. Просто бинарные деревья

2. Упорядоченные бинарные деревья (деревья поиска)

3. AVL-деревья (балансируемые) деревья

4. Идеально-сбалансированные деревья

 

Упорядоченные бинарные деревья

17, 18, 6, 5, 9, 23, 12, 7, 8

                                           17                                 корень (0-ой уровень)

                           6                         18                      уровень 1 (слой 1)

           5                         9                         23      уровень 2

                           7                         12                     уровень 3

                                           8 11                                  уровень 4

Глубина – 5

Левое поддерево и правое.

Если правое и левое деревья заполнены полностью, то такое дерево – полное. Эффективность поиска на дерево O (log2n). Если дерево вырожденное (неполное) - поиск линейный, неэффективный. Дерево балансируют (AVL), выполняя требования – высота левого и правого дерева не должна отличаться более чем на 1.

Если узел не имеет потомка – лист, если имеет – ветвь.

 

Идеально-сбалансированное дерево

Чтобы его построить, нужно знать количество узлов, т.к. алгоритм требует знания количества узлов.

1. Взять одну вершину (узел) в качестве корня

2. Построить тем же способом левое поддерево с nl=n/2 узлами.

3. Построить тем же способом правое поддерево с nr=n-nl-1 узлами.

В данном дерево количество узлов в левом и правом поддеревьях не отличается больше, чем на 1.

 

Бинарные деревья п.1 не являются упорядоченными, они строятся для различных целей, например для пирамидальной сортировки.

 

Удаление узла из упорядоченного дерева

Возможны 3 случая:

1. Удаляемый узел – лист

Удалить ссылку на элемент, освободить память

2. Из удаляемого узла выходит только 1 ветвь

Переназначают указатель, освобождают память

3. Из удаляемого узла выходят 2 ветви

Чтобы сохранить упорядоченность дерева, удаляемый узел заменяют либо крайним правым узлом левой ветви, либо крайним левым узлом правой ветви

 

Способы обхода дерева

В общем виде дерево выглядит

  R

A        B

Способы обхода:

1. Слева направо – A R B

2. Сверху вниз – R A B

3. Снизу вверх – A B R

4. Справа налево – B R A

(a+b/c)*(d-e*f)

 

● Применим запись ARB

(a+b/c)*(d-e*f)

Сортировка массива по возрастанию (BRA – по убыванию)

● ABR

abc/+def*-*

постфиксная запись

● RAB – префиксная запись

*+a/bc-d*ef

 

Набор функций для работы с деревом

Дерево является рекурсивной структурой данных, поэтому естественно использовать рекурсивные функции, но это не всегда удобно.

1. Формирование первого узла дерева – корня

2. Включение узла в дерево

3. Функция поиск по дереву

4. Функция обхода дерева

5. Удаление узла

6. Уничтожение дерева

 

8.Файлы в СИ

Все файлы рассматриваются как неструктурированная последовательность байтов. Операции ввода-вывода, связанные с файлами, осуществляются библиотечными функциями.

Существует 2 уровня ввода-вывода:

1. Верхний – потоковый

2. Нижний

Функции верхнего уровня потокового ввода-вывода

 

При чтении из файла данные помещаются в буфер (под него выделена динамическая память), затем данные побайтно или определенными порциями передаются в программу. При опустошении буфера в него передается следующая порция данных. При выводе или записи в файл данные из программы передаются в буфер, когда буфер будет заполнен – они одним блоком выводятся в файл (за одно обращение к диску). Буфер сокращает временные затраты на взаимодействие программы с диском. Файл вместе со средствами буферизации называют потоком, но обычно вместо слова поток используют слово файл, подразумевая поток. Обмен данными программы с файлами осуществляется функциями библиотеки ввода-вывода.

Они могут:

1. Открывать и закрывать потоки (файл)

2. Вводить и выводить символы, строки, форматированные данные, определенную порцию данных

3. Анализировать ошибки и в соответствии с ошибкой выводить сообщение

4. Управлять размером буфера и буферизацией потока

5. Позиционировать файл, т.е. указатель файла ставить в определенную позицию

Все функции находятся в файле <stdio.h>

#include <stdio.h>

FILE*fp;                                                                                                           // fp – указатель на поток (файл),

FILE - структурный тип, он предопределен, там находится:

1. Указатель на буфер

2. Указатель текущей позиции в файле

 

Fp=fopen (имя_файла (можно указатель на строку), режим_открытия (можно указатель на строку));

Fp=fopen (“t.txt”, “w”);                                                                           // при выполнении функции fopen выделяется динамическая память под буфер, буфер связывается с файлом на диске, т.е. образуется поток, адрес буфера помещается в указатель fp, физически существующему файлу на диске t.txt в программе будет соответствовать имя fp.

Fp=fopen (“z:\\h\data” , “rb+”);

 

Файл может быть открыт в одном из 6 режимов:

1. “w” – новый текстовый файл открывается для записи, если он уже существует, то его содержимое стирается, т.е. файл создается заново

2. “r” – уже существующий файл открывается только для чтения

3. “w+” – в отличие от “w” можно делать исправления в файле, файл может увеличиваться в размерах, т.е. «расти»

4. “r+” – в отличие от “r” в файле можно делать изменения (редактировать), но «расти» он не может

5. “a” – (append) – текстовый файл открывается (или создается, если его нет) для добавления в него новой информации в конец

6. “a+” – в отличие от “a” можно его изменять в любом месте, файл может «расти»

Файл можно открыть в 2-х режимах:

1. В текстовом (читальный) – отличается тем, что последовательность символов CR (возврат каретки, код 13) и перевод строки LF (код 10) при чтении из файла преобразуются в символ перевода строки ‘\n’ (код 10, в ОП). При выводе в файл – обратное преобразование. Режим по умолчанию - “wt” / “w”

2. В бинарном (прочитать нельзя) – обмен данными осуществляется побайтно, поэтому преобразований нет, открывается – “wb” / “rb”.

Режимы с плюсом: - в этом случае переход от записи к чтению можно делать после того, как указатель файла поставлен в соответствующую позицию, т.е. выполнено позиционирование файла

 

Ошибки

При открытии файла могут возникнуть следующие ошибки:

1. Указанный файл не найден (при чтении)

2. Нет места на диске (при записи)

3. Диск защищен от записи

Всего больше 10 ошибок, они нумеруются. Чтобыузнать ошибку используют последовательность операторов

функция закрытия файла

Функция закрытия файла – int fclose(fp);   , выполнение функции: данные в буфере, не выведенные на диск, выводятся на диск, данные в буфере, не использованные программой, теряются, динамическая память, выделенная под буфер, освобождается, связь программы с файлом прекращается.

Если нет функции – произойдет ошибка. Чтобы не было потери данных при выводе в файл, файл нужно закрывать явно функцией fclose.

 

Функции библиотеки для работы с файлом в текстовом режиме:

1. Fgetc() – прочитать один символ из файла

2. Fputc() – вывести в файл один символ

3. Fprintf() – форматированный вывод в файл

4. Fgets() – чтение строки из файла

5. Fscanf() – форматированный ввод (чтение) из файла

6. Fputs() – запись строки в файл

7. Int feof (fp) – проверяет состояние индикатора конца файла, если индикатор показывает конец файла, то функция возвращает не нуль

Примеры функций:

1. Fgets (str, 50, fp);

50 – количество считываемых символов + ‘\0’, считать можно только 49 символов, если до 49-ого символа прочитали ‘\n’, то он переносится в строку str.

Из файла fp прочитывается 49 символов. Функция возвращает или адрес прочитанной строки, или NULL при достижении конца файла или в случае ошибки

2. Fputs (str, fp);

Строка str выводится в файл fp, возвращает код последнего символа в случае успеха и NULL в случае ошибки. Строку в файле автоматически не переводит. В файл может вывести только строку, ограниченную ‘\0’, если нуля нет – может быть зацикливание. Символ ‘\0’ – в файл не переносим, перевод строки ‘\n’ – не записывают.

 

Функции в бинарном режиме:

Int c;

C=gets (fp);

Puts(c, fp);                         

Из переменой c выводится в файл fp, обмен побайтно, но может происходить и порциями данными определенной длины, тогда используются функции:

1. Fread (ptr, size, N, fp); - для чтения из файла

2. Fwrite (ptr, size, N, fp); - для записи в файл

Выполнение функции fread – из файла fp выводится N элементов по size байт каждый в область памяти, адресуемую ptr.

Выполнение фукнции fwrite – из области памяти, адресуемую ptr, в файл fp выводится N элементов по size байт каждый.

Эти функции особенно удобны при работе с файлами структур. В этом случае N – размер массива структур. Size – объем памяти, занимаемой структурой.

 

Позиционирование файла (работа с файлом, как с массивом) – произвольный доступ к файлу

Используют функции:

1. Int fseek (указатель, смещение, начало отсчета);

Указатель – указатель на файл, fp

Смещение – тип long, может быть >0 (если смещаемся к концу файла) или <0 (к началу файла)

Начало отсчета – параметр кодируется, если 0, то начало отсчета – начало файла, если 1 – текущая позиция файла, 2 – конец файла

В случае успеха возвращает NULL, а в случае неуспеха возвращает -1 (при попытке сместиться на пределы файла).

Примеры использования:

a. Fseek (fp, 0L, 0); - перемещение к началу файла из произвольной позиции

b. Fseek (fp, 0L, 2); - к концу файла из произвольной позиции

c. Struct {…} st;

Fseek (fp, -(long)sizeof(st), 1); - указатель текущей позиции в файле перемещается к началу файла на 1 структуру.

 

2. Long ftell (fp); - возвращает текущую позицию в файле

3. Void rewind (fp); - устанавливает указатель на начало файла

 

9.Файлы в Си++

Для ввода-вывода используются объекты классов. Буфер в Си заменяется здесь на объект существующего класса.

Иерархия классов ввода-вывода:

 

 

Режимы открытия файлов в Си++

1. ios::in – открыть файл для чтения или ввода

2. ios::out – открыть файл для записи или вывода

3. ios::app – записывать все данные в конец файла

4. ios::ate – переместиться в конец исходного открытого файла, но данные могут быть записаны в любом месте файла

5. ios::trunс – если файл существует, то его содержимое – отбросить, тоже по умолчанию для режима out

6. ios::nocreate – если файл не существует, то он и не открывается

7. ios::norlace – если файл существует – то он не открывается

 

 

Реализация динамических структур с помощью массивов

Это возможно когда заранее известен полный объем данных

Стек

Для реализации стека кроме массива данных нужна одна вспомогательная переменная, куда заносится индекс вершины стека.

Очередь

Для реализации очереди кроме массива данных нужны 2 вспомогательные переменные, в а – заносится индекс начала очереди, в b – индекс конца, с течением времени они возрастают.

Линейный список

Вывод:

Недостаток реализации:

1. динамических структур с помощью массива – необходимо до выполнения программы знать объем данных (на практике – не часто).

Достоинства:

1. Используются непрерывные участки памяти (под массивы),

2. Можно сортировать, в общем случае, упорядочивать большие объемы данных без физического их перемещения в памяти

 

Неформатированный ввод-вывод в файлах СИ++

Infile.read ((char*)&s, sizeof(s));                         // чтение

Outfile.write ((char*)&s, sizeof(s))                     // запись

 

Позиционирование в файлах Си++

1. Infile.seekg (n);                                                           // позиционирование на n-ый байт от начала файла

Infile.seekg (n, ios::beg);                         // это же самое

2. Infile.seekg (n, ios::cur);                          // позиционирование на n-ый байт вперед от текущей позиции

3. Infile.seekg (n, ios::end);                        // … от конца файла

4. Infile.seekg (0, ios::end);                         // указатель на конец файла

5. Outfile.seekp (…);                                      // для файла открытого на запись

 

 

Функции, позволяющие получить текущую позицию указателя файла

1. Long l=infile.tellg ();                   // возвращает текущую позицию указателя в файле открытого для чтения

2. Long l=outfile.tellp ();               // возвращает текущую позицию указателя в файле открытого на запись

 

Файлы в СИ++ подразделяются на:

1. Файлы с последовательным доступом

2. Файлы с произвольным доступом (записи имеют одинаковую длину), самый быстрый доступ, поэтому такие файлы используются в системах по обработке запросов

 

Перегрузка операций

Чтобы известными операциями пользоваться для любых типов данных, также как для стандартным, эти операции надо перепрограммировать, т.е. перегрузить ( чтобы использовать пользовательский тип). Перегружать можно любые операции, кроме:

1. Операция точка .

2. Операция стрелка точка →.

3. Операция точка звездочка .*

4. ?:

5. ::

6. #

7. ##

8. Sizeof

 

Правила перегрузки операций:

1. Сохраняется количество аргументов, приоритеты и правила ассоциации, принятые для стандартных типов данных

2. Перегружать операции для стандартных типов данных нельзя

3. Функции операций, которые используются для перегрузки операций, не могут иметь аргументов по умолчанию

4. Функции операций наследуются, за исключением операции присваивания =

5. Функции операции не могут быть статическими (static – не могут использоваться)

 

Перегрузка операций осуществляется с помощью специальных функций – функций операции:

Тип operator <символ операции> (список параметров)

Operator <символ> - имя функции

Можно использовать функции как:

1. Функция - элемент класса

2. Дружественная функция или друг

3. Просто функция

Примечание: операцию нельзя перегрузить с помощью функции элемента, первый параметр которой не имеет тип class.

 

Перегрузка унарных операций

++

--

1. префиксный инкремент

1. Как функция элемента класса

class time {

-----------

Time&operator ++ () {++h; return *this;}

2. Как дружественная функция

class time {

-----------

Friend time&operator ++ (time & t);

-----------

Time & operator ++ (time &t) {++t.h; return t;}

Дружественная функция не является функцией элемента класса, но она имеет доступ к закрытой части класса через имя объекта, через указатель, через ссылку на объект, она нарушает закрытость класса, но на практике бывает необходимо ее использовать.

3. Как просто функция - функция определена вне класса

Time & operator ++ (time&t)

{ int k=t.geth ();

K++;

t.seth(k);

return t;

}

 

 

2. Операция постфиксного инкремента

Class time {

-------------

Time operator ++ (int – формально, для отличия) {h++; time t(*this); return t; }

Void main ()

{time t;

Cout << (t++).geth();

}

 

Перегрузка бинарных операций

Имеет 2 операнда, первым операндом является тот объект класса, для которого вызывается данная функция, а вторым – объект, переданный в функцию.

Class time

{

-------------

Bool operator > (const time & t)

{if (h>t.geth()) return true;

Return false;

------------

}

};

 

Void main ()

{time t1, t2;

--------------

If (t1>t2) ----

--------------

}

 

Перегрузка просто функцией:

Bool operator > (const time&t1, const time&t2)

{if (t1.geth()>t2.geth()) return true;

Return false;

}

 

Перегрузка операции приведения типа

Operator имя_нового_типа ();

 

Time :: operator int ()

{return h;}

-------------

Time t;

Cout<< int(t);

 

Перегрузка операции индексирования

Язык Си и Си++ не позволяет контролировать выход за пределы массива, использование классов и перегрузки индексирования преодолевает этот недостаток.

 

           Int &vector :: operator[] (int i);

{if(i<0 || i>=size)

{cout<< “Неверный индекс” i=” << I << “ Завершение программы” <<endl;

Exit (0);

}

Return p[i];

Композиция классов

Состоит в том, что объекты одних классов являются элементами других классов.

Class date

{public:

           Date (int=1, int=1, int=1980);

           Void print() const;

Private:

           Int m, d, y;

};

 

Class employee

{public:

           Employee (char*, char*, int, int, int, int, int, int);

           Void print () const;

Private:

           Date bdat;                                                      // дата рождения

           Date hdat;                                                      // дата приема на работу

};

 

Employee::employee (char*f, char*l, int bm, int bd, int by, int hm, int hd, int hy)

: bdat (bm, bd, by), hdat (hm, hd, hy)                // инициализаторы элементов, служат для вызова конструктора класса date, если инициализаторов нет – вызывается конструктор с умолчанием, если и его нет, то – ошибка.

{ -----};

 

Void main();

{employee e {”Петров”, “Иван”, 7, 24,1979, 6, 11, 2000};

-----------

}

 

Дружественные функции класса, дружественные классы

#include <iostream.h>

Class count

{friend void setx (count&, int);

Public:

           Count() {x=0;}

           Void print () const {cout << x << endl;}

Private:

           Int x;

};

 

Void setx (count &c, int v)

{c.x = v;}                                                                          // дружественная функция имеет доступ к закрытой части класса через ссылку

 

Дружественный класс

Если нужно чтобы функции элементов одного класса имели доступ к данным элементам и функциям другого класса, то первый класс объявляется дружественным ко второму.

Class BinSTree;

Class TreeNode

{friend class BinSTree;                                                  

// функции элемента класса BinSTree получают доступ к элементам класса TreeNode

-----

}

Использование указателя this

В функциях - элементах класса:

Функции-элементы имеют прямой доступ к указателю на объект, для которого эта функция вызывается, обычно указатель используется неявно, но можно и явно.

 

При открытом наследовании

1. Закрытые элементы базового класса доступны в базовом классе элементам и друзьям базового класса

2. Защищенные элементы базового класса доступны элементам и друзьям как базового, так и производного класса

3. Открытые элемента базового класса доступны всем функциям, доступ через имя объекта

4. Элементы производного класса ссылаются на элементы базового класса просто по имени

 

При закрытом наследовании:

1. Некоторые функции класса можно сделать доступными

Class B

{…

public:

           Void f();

….

}

 

Class A : private B

{…

Public:

           B::void f();

}

 

Пример простого наследования:

#include <iostream.h>

#include <iomanip.h>

Class point                                                                                                     // базовый класс - точка

{friend ostream& operator << (ostream&, const point&);            

// первый параметр функции – не является объектом данного класса и поэтому эта функция не может быть функцией-элементом класса, но так как она должна иметь доступ к закрытой части класса, где находятся координаты точки, она объявляется дружественно.

Public:

           Point (float=0, float=0);            // конструктор с умолчанием

           Void setpoint (float, float);     // функция установки координат

           Float getx () {return x;};

           Float gety () {return y;};

Protected:

           Float x, y;

};

 

Примечание: в одиночном классе спецификаторы private и protected равноценны, т.е. доступ к элементам в этих разделах возможен только через функции-элементы открытой части, а при наследовании большая разница – элементы в разделе private остаются в производном классе недоступными, а в protected – доступны.

Point :: point (float a, float b)

{setpoint (a,b);

}

 

Void point :: setpoint (float a, float b)

{x=a;

y=b;

}

 

// вывод данных в форме [x,y],

Ostream & operator << (ostream & output, const point & p)

{output << ‘[‘ << p.x << ‘,’ << p.y << ‘]’ ;

Return output;

}

 

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

P1, p2, p3

….

Cout << p1 << p2 << p3

Class circle :: public point                                         // производный класс - окружность

{friend ostream & operator << (ostream &, const circle &);

Public:

           Circle (float r=0.0, float x=0.0, float y=0.0);

           Void setradius (float);                               // установка радиуса

           Float getradius () const;                           // возвращение радиуса

Protected;

           Float radius;

}

 

Circle :: circle (float r, float a, float b)

: point (a, b)                                                                      

// вызов конструктора базового класса в списке инициализацией (явно)

{radius=r;

}

 

// вывод данных объекта circle в форме: Центр =[x,y]; Радиус = #.##

Ostream & operator << (ostream & output, const circle & c)

{output << “Центр =[ ” << c.x << ‘, ’ << с.y << “]; Радиус = ” << setiosflags (ios::showpoint) << setprecision (2) << c.radius;

Return output;

}

 

Void main ()

{point * pptr, p (3.5, 5.3);

Circle *cptr, с (2.7, 1.2, 8.9);

Cout << “p:” << p << endl;                      // p:[3.5, 5.3]

Cout << “c:” << с << endl;                        // Центр =[1.2, 8.9]; Радиус=2.70

// рассмотрение объекта с как объект р

Pptr=&c;

Cout << endl << “с через *pptr : ” << *pptr <<endl;                       

// с через *pptr: [1.2, 8.9], следовательно производный класс является и базовым

// рассмотрение объекта с после приведения типа pptr

Cptr =(circle* ) pptr;                                  // приведение базового типа к производному типу

Cout << endl << “c через *cptr: “ << *cptr << endl;

// с через *cptr: Центр = [1.2, 8.9]; Радиус = 2.70;

Для того, чтобы через указатель на базовый класс pptr увидеть объект производного класса с необходимо:

1. Присвоить указателю pptr адрес объекта с

2. А затем указатель pptr привести к типу производного класса

 

Pptr=&p;

Cptr = (circle * )pptr;

Cout << endl << “p через *cptr : ” << *cptr << endl;

// p через *cptr : Центр = [3.5, 5.3]; Радиус = 4.02e-38

Примечание: если указателю pptr присвоить адрес объекта р, а затем привести к типу производного класса, то через этот указатель будет виден только базовый класс.

}

 

Примечание:

1. Производный класс наследует функции-элементы setpoint, getx, gety и данные-элементы x, y из базового класса

2. В производном классе введены данные-элемент radius, определен собственный конструктор, добавлены функции-элементы setradius и getradius

3. В базовом классе используется спецификатор protected, чтобы x и y были доступны в производном классе

Правила наследования функций-элементов

Наследуется все, кроме:

1. Конструкторов

2. Операций присваивания

3. Деструкторов

 

1. Конструкторы не наследуются, поэтому производный класс должен иметь свой собственный конструктор.

Порядок вызова конструктора производного класса следующий:

● Если в производном классе конструктор не имеет явного вызова конструктора базового класса, то автоматически вызывается конструктор базового класса с умолчанием, т.е. тот, который можно вызвать без параметров

● Если конструктор базового класса требует указания параметров (наш случай), он вызывается в конструкторе производного класса в списке инициализации

● Если базовых классов несколько (множественное наследование), то их конструкторы вызываются в порядке объявления

● В иерархии, состоящей из нескольких уровней, конструкторы базовых классов вызываются, начиная с самого верхнего уровня, после этого вызываются конструкторы классов для создания объектов, которые используются в производном классе, как элементы, и в последнюю очередь вызываются конструкторы производного класса

 

2. Вызов деструкторов:

● Если в производном классе нет деструктора, то он формируется по умолчанию, и вызывает деструкторы всех базовых классов

● В отличие от конструкторов, деструкторы не требуют явного вызова деструкторов базового класса, т.к. это делается автоматически

3. В иерархии их нескольких классов деструкторы всегда вызываются в последовательности, обратной вызовам конструкторов, т.е. вначале деструктор производного класса, потом стоящего над ним и т.д. до начала иерархии.

 

Windows программы Builder

Как и все С, С++ программы состоят из объявлений (переменных, классов, типов, функций) и определений функций.

Среди этих функций есть главная – WinMain, она начинает выполнение программы. Функция обычно самая короткая из всех функций и выполняет только некоторые подготовительные операции:

1. Инициализирует объекты-компоненты и объект-форма

Затем выполнение программы сводится к событиям в объектах-компонентах и передаче результатов в другие объекты-компоненты, как правило, это происходит при участии пользователя. Все объекты-компоненты размещаются в формах, каждой форме соответствует свой модуль, модуль имеет 2 файла:

1. Заголовочный файл

2. Файл реализации

Реализуется принцип сокрытия информации. Следовательно, windows программы строятся по модульному принципу. На основе написанного кода создается выполняемый файл (модуль) в результате выполнения следующих этапов:

1. Препроцессор – преобразует исходный текст в соответствии с директивами препроцессора, например – включает текст одних файлов в тексты других и т.д.

2. Компилятор – переводит тексты модулей в машинный (объектный) код, для каждого исходного файла создается объектный файл с расширением *.obj

3. Компоновщик – объединяет объектные файлы в единый загружаемый и выполняемый модуль с расширением exe, модуль запускается на выполнение

В процессе проектирования Builder автоматически создает головной файл проекта с функцией WinMain, заголовочные файлы и файлы реализации, однако пользователь может делать соответствующие добавления в заголовочный файл и файл реализации модуля Form.

Головной файл с функцией WinMain, как правило, пользователем не изменяется, рекомендуется его не изменять, и обычно он не просматривается.

 

Структура головного файла проекта

Имеет проект одну форму

#include <vcl.h>                          // visual component library

#pragma…

USERES (“Project1.res);           /макрос, подключающий файл ресурсов (пиктограмма, изображение)

USEFORM (“Unit1.cpp”, Form1);          // макрос ,подключающий файл формы

 

WINAPI WinMain (параметры)

{try                                                    // попытка начать выполнение

           {инициализация объектов-компонентов

            инициализация объектов формы

           }                                         // начало выполнения программы

 Catch (параметры)                  // раздел поимка

           {код, исполняемый в случае ошибки (обработка исключений – аварийных ситуаций), по умолчанию – стандартный обработчик исключений

           }

 Return 0;

}

 

Структура заголовочного файла модуля формы

Содержит директиву условной компиляции.

#ifndef Unit1H

#define Unit1H

//--------------

#include…..                    // директивы помещаются автоматически, они подключают копии файлов , в которых описаны компоненты, переменные, функции, используемые в данном модуле.

#include <math.h>                     // директива пользователя

 

// объявление класса формы TForm1

Class TForm1 : public TForm

{_published:                     

// публикует, открытый раздел, содержит объявление размещенных на форме компонентов и обработчиков событий в них, создается раздел автоматически, вмешиваться в этот раздел запрещено

           TButton *Button1;

           TLabel *Label1;

Void fastcall Button1Click (TObject*Sender);

Private:

// пользователь может здесь разместить объявление типов, переменных, функций, недоступных для других модулей.

           Void __fastcall F1(char ch);     // функция доступна только в данном модуле

           Char ch6;                                        // переменная доступна только в данном модуле

Public:

           __fastcall TForm1 (TComponent *Owner);     // конструктор формы

// сюда можно поместить объявление типов, переменных, функций, доступных для других классов и других модулей

           Char ch1;

           Void __fastcall F2(char ch);     // доступны для объектов любых классов и других модулей, но со ссылкой на объект данного класса.

};

 

Extern…..

 

// после объявления класса формы можно поместить объявление типов, переменных, функций, которые не включаются в класс Form.

 

Char ch2;                                                        // ch2 – глобальная переменная, она доступна в пределах данного модуля, и будет доступна в других модулях, если там повторить ее объявление со спецификацией extern.

Void F3 (char ch);                                        // F3 – глобальная функция, она доступна в пределах данного модуля, и будет доступна в других модулях ,если в них повторить ее прототип.

 

#endif;

 

Структура файла реализации модуля Form

#include <vcl.h>

#pragma

#include UnitH             // включаются автоматически

//-----------------

#pragma…

#pragma…

#pragma…                      // включаются автоматически

// здесь могут быть включены директивы, нужные пользователю

#include <math.h>

TForm1 *Form1;          // указатель на объект формы, включается автоматически

// определение конструктора фомы

__fastcall TForm1 ::TForm1 (TComponent *Owner)

: TForm (Owner);

{//тело конструктора пустое, сюда могут быть включены операторы, выполняющие нужные действия при создании форм

}

// здесь могут быть объявлены глобальные переменные, доступные в данном модуле, и которые будут доступны в других модулях, если там повторить их объявление со спецификацией extern, здесь же могут быть определены функции, не объявленные ранее, и должны быть определены все функции, объявленные в заголовочном файле.

 

Char ch3;

Void F4 (char ch)

{Form1->Label1->Caption=Form1->Label1->Caption+ch+Form1->ch1;              // функция классу не принадлежит, поэтому доступ к компоненту label через имя объекта form1 и доступ к переменой ch и ch1, которая находится в public класса через имя объекта form1

}

 

Void __fastcall TForm1 ::F1 (char ch);                 // f1 – принадлежит классу, находится в private, поэтому доступ по имени компонента

{label1->caption=label1->caption+ch+ch1;

}

 

Void __fastcall TForm1 ::F2 (char ch);                 // f2 – принадлежит классу, находится в public

{label1->caption=label1->caption+ch+ch1;

}

 

Void F3 (char ch);                                                        // f3 – не принадлежит классу,

{form1->label1->caption=form1->label1->caption+ch+form1->ch1;

}

 

Void __fastcall TForm1 ::Button1Click (Tobject *Sender);                             

{ch1=’-‘;

ch2=’A’;

ch3=’B’;

ch4=’C’;

label1->caption=””;

F1(ch1);

F2(ch2);

F3(ch3);

F4(ch4);

Label1->Font->Color=clRed;

}

 

Структуры.

Форматы определения структурного типа.

1) struct имя_структурного_типа{определение элементов}

2) typedef struct{определение_элементов}имя_структурного_типа

3) typedef struct имя_структурного_типа_1

{определение элементов}имя_структурного_типа_2

4) #define STUD struct{char f[10], int nz;}

При определении структурного типа память не выделяется. Для выделения памяти под структурный тип, нужно объявить объект структурного типа.

Форматы определения объектов:

1) имя_структурного_типа список_объектов;

2) struct имя_структурного_типа{определение_элементов}список_объектов;

3) struct {определение_элементов}список_объектов//когда имя не требуется

Память, выделяемая под объекты структурного типа.

Struct st

{int i;

float f;

char ch;

}s( ← имя объекта структурного типа);

   I       f       ch

|__ __|__ __ __ __|__|

2 б        4 б   1 б

sizeof(имя_структурного_типа);

sizeof(имя_объекта_структурного_типа);//можно без скобок

Операции над объектами структурного типа.

1) Разрешена инициализация.

2) Присваивание однотипных структур.//наиболее используемая из операций

Операция присваивания для объектов структурного типа в статической памяти выполняется по умолчанию, как побитовое копирование.

3) Сравнение поэлементно.

Доступ к элементам определения структурного типа.

1. С помощью операции «точка»:

имя_объекта.имя_элемента

goods tea; tea.price;

2. С помощью операции «стрелка» :

goods*tovar;

tovar → name;

Структуры, массивы и указатели.

1. В качестве элементов структуры можно использовать массив:

Struct

{double m;

float coord[3];

}point={12.3, {-1.0, 2.2, -4.3}};

point.coord[0];

2. В качестве элементов структуры можно использовать ранее определенные структуры.

struct date {int d, m, y};

struct goods{…

                           date data;}yea;

tea.data.y;

3. Массивы структур.

complex set[80]={{…}{…}{…}…{…}};( ← 80 структур)

4. Указатели на структуры, ссылки, массивы.

struct{…}point( ← имя_объекта);&pp( ← ссылка)=point, *pptr( ← указатель) =&point( ← адрес point);

point1[30];

point1 –имя указателя или константна указателя

point1[5];

pptr=point1;

pptr++;//операция инкремента

pptr--;//операция декремента

Элементы структурного типа не могут быть не определены выше структуры, но могут быть указателем на определяемую структуру.

Struct stud

{int nz;

char f[10];

stud *uk;} – это позволяет использовать динамические структуры данных для случаев когда объем данных не известен даже во время выполнения программы

Объединения (смешения).

union sm( ← имя типа объединения)

{int i;

float f;

char ch;

}U;

Доступ:

U.f

ch i f

|__ |__|__ __|

 1б 2б 4б

Тип объединения можно использовать, когда элементы используются поочерёдно. Объединения часто использовались в составе структур

Struct st

{char ch[5];

int i;

union{int a;

           float b;

           char c[7];

           }UV;

}dat;

Доступ:

dat.UV.c[5];

Тип перечисление.

Есть две формы определения переменных типа перечисление.

1. enum{список_значений}имя_переменной;

enum{kr, gel, zel}svetofor;

2. enum имя_типа_перечисления{список_значений};

имя_типа_перечисления имя_переменной;

enum typsvet{kr, gel, zel};

typsvet svetofor;

Последовательность значений автоматически нумеруется от 0 и т.д. до 255:

enum typsvet{kr=1, gel, zel};

Или значения можно задавать самому:

enum typsvet{kr=5, gel=10, zel=100};

Допустимые операции над переменными типа перечисление.

1. Можно присваивать значения константам того же типа.

svetofor=kr;

2. Разрешены операции проверки на равенство(==) и неравенство(!=).

3. Можно использовать в качестве оператора switch.

4. В качестве индексов элементов массива.

5. Выводить в качестве значений целого типа.


Поделиться:



Последнее изменение этой страницы: 2019-05-08; Просмотров: 432; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.72 с.)
Главная | Случайная страница | Обратная связь