Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
oop.doc
Скачиваний:
4
Добавлен:
01.04.2025
Размер:
248.32 Кб
Скачать

Void main()

{ int n=4;

int X[ ]={10,20,30,14};

cout << “\n rmax(n,X) = “ << rmax(n,X);

rmax(n,X)=0;

for ( int i=0; i<n; i++)

cout << “\t X[“<<i<<“] =“ <<X[i];

float arx[ ]={10.3,20.4,10.5};

cout << “\n rmax(3,arx) = “ << rmax(3,arx);

rmax(3,arx)=0;

for (i=0; i<3; i++)

cout << “\t arx[“<<i<<“] =“ <<arx[i];}

Результат

rmax(n,x)=30 X[0]=10 X[1]=20 X[2]=0 X[3]=14

rmax(3,arx)=20.4 arx[0]=10.3 arx[1]=0 arx[2]=10.5

Основные свойства параметров шаблона:

- имена шаблона должны быть уникальны во всем определении шаблона;

- список параметров шаблона не может быть пустым;

- в списке параметров шаблона функции может быть несколько параметров. Каждый из них должен начинаться служебным словом class;

- недопустимо использовать в заголовке шаблона параметры с одинаковыми именами;

- имя параметра шаблона имеет в определяемой шаблоном функции все права имени типа.

2

Из основных типов языка С++ пользователь может конструировать производные типы, например структуры и объединения. Структуры и объединения отнесены к структурированным типам.

Структура как составной тип данных

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

  • заглавие книги; количество страниц.

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

struct card {char *author; // Ф.И.О. автора книги

char *title; // Заголовок книги

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

Такое определение вводит новый производный тип, который называется структурным типом. В данном примере у этого структурного типа есть конкретное имя card .

В соответствии с синтаксисом языка определение структурного типа начинается со служебного слова struct, вслед за которым помещается выбранное пользователем имя типа. Описание элементов, входящих в структуру, помещаются в фигурные скобки, вслед за которыми ставится точка с запятой. Элементы структуры могут быть как базовых, так и производных типов. Например, в структурах типа card будут элементы базового типа int и производного типа char * .Определив структурный тип, можно определять и описывать конкретные структуры, т. е. структурированные объекты, например, так : сard rec1, rec2;

Здесь определены три структуры (три объекта) с именами rec1, rec2,. Каждая из этих структур содержит в качестве элементов свои собственные данные: char *title;

char *city; состав которых определяет структурный тип с именем card.

Если структура определяется однократно, т.е. нет необходимости в разных частях программы определять или описывать одинаковые по внутреннему составу структурированные объекты, то можно не вводить именованный структурный тип, а непосредственно определять структуры одновременно с определением их компонентного состава. Следующий оператор определяет две структуры с именами XX, YY, массив структур с именем ЕЕ и указатель pst на структуру: struct { char N[12]; int value; } XX, YY, EE[8], *pst;

В ХХ, YY и в каждый элемент массива EE[0],...,EE[7] входят в качестве элементов массив char N[12] и целая переменная value. Имени у соответствующего структурного типа нет.

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

Например, для определенной выше структуры YY оператор YY.value = 86;

присвоит переменной value значение 86 .

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

card dictionary= {“ Hornby A.S.”, ”Oxford students\

dictionary of Current English”, “Oxford”, “Oxford University”, 1994, 769 };

С именем структурного типа не связан никакой конкретный объект, и поэтому с его помощью нельзя сформировать уточненные имена элементов. Определение структурного типа вводит только шаблон (формат, внутреннее строение) структур. Идентификатор card в примере - это название структурного типа (т.е. “ярлык” или “этикетка” структур, которые будут определены в программе).Определение структурного типа может быть совмещено с определением конкретных структур этого типа: struct PRIM {char *name; long sum; } A, B, C;

Здесь определен структурный тип с именем PRIM и три структуры A, B, C, имеющие одинаковое внутреннее строение. Так как имя структурного типа обладает всеми правами имен типов, то разрешено определять указатели на структуры:

имя_структурного_типа *имя_указателя_на_структуру;

Как обычно, определяемый указатель может быть инициализирован. Значением каждого указателя на структуру может быть адрес структуры того же типа, т. е., грубо говоря, номер байта, начиная с которого структура размещается в памяти. Структурный тип задает ее размеры и тем самым определяет, на какую величину (на сколько байтов) изменится значение указателя на структуру, если к нему прибавить 1. Например, после определений структурного типа card и структуры rec2 можно так записать определение указателя на структуру типа card: card *ptrcard = &rec2;Здесь определен указатель ptrcard и ему с помощью инициализации присвоено значение адреса одной из конкретных структур типа card. После определения указателя появляется еще одна возможность доступа к элементам структуры rec2. Ее обеспечивает операция ‘->‘ доступа к элементу структуры, с которой в этот момент связан указатель. Формат выражения таков:имя_указателя -> имя_элемента_структуры

ptrcard -> pages Вторая возможность обращения к элементу структуры с помощью адресующего ее указателя - это разыменование указателя и формирование уточненного имени такого вида: (*имя_указателя) .имя_элемента_структуры

Т.е. следующие три выражения эквивалентны: (*ptrcard) .pages

ptrcard -> pages rec2 .pages

они имеют один и тот же элемент int pages конкретной структуры rec2, имеющей тип card. Как и для других объектов, для структур могут быть определены ссылки:

имя_структурного_типа& имя_ссылки_на_структуру_инициализатор; Например, для введенного выше структурного типа PRIM можно таким образом ввести ссылки на структуры A, B: PRIM& refA = A; PRIM& refB (B);

После таких определений refA есть синоним имени структуры А, refB есть другое имя для структуры В. Теперь возможны, например, такие обращения: A .sum эквивалентно refA.sum;

  • *B .name эквивалентно *refB .name; A .name эквивалентно refA.name.

Спроектируем простейшую базу данных, построив ее в виде двухсвязного списка структур (рис. 4), каждая из которых имеет такой формат:

struct record { card book; // Структура с данными о книге

record *prior; // На предыдущий элемент списка

record *next; // На следующий элемент списка };

Структурный тип record предусматривает, что в каждую структуру входят три элемента: структура типа card и два указателя на структуры типа record. Предполагается, что до определения структурного типа record уже определен структурный тип card.

Указатель на структуру может входить в определение того же структурного типа. Именно так в определении формата структуры record введены два указателя: record *prior - указатель на предыдущий элемент в двухсвязном списке структур; record *next - указатель на следующий элемент. При определении с помощью typedef имени для структурного типа, у последнего может отсутствовать основное имя. Например, структурный тип можно ввести и следующим образом: typedef struct { char *name; long sum; } STRUCT; STRUCT struct_st , *struct_ps , struct_as[8];

В данном примере имя типа STRUCT вводится с помощью typedef для структуры, тип которой не поименован. Затем имя типа STRUCT используется для определения объектов. Таким образом, имеются две возможности определения имени структурного типа.

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

struct mistake { mistake s; int m; }; // Ошибка!

В то же время элементом определяемой структуры может быть указатель на структуру определяемого типа: struct correct {correct *ps; long f; }; // Правильно!

Элементом определяемой структуры может быть структура, тип которой уже определен: struct begin { int k; char *h; } strbeg; struct next {begin beg; float d; };

Если в определении структурного типа нужно в качестве элемента использовать указатель на структуру другого типа, то разрешена такая последовательность определений:

struct A; struct B { struct A *pa; }; struct A{ struct B *pb; };

Неполное определение структурного типа А можно использовать в определении структурного типа В, так как определение указателя pa на структуру типа А не требует сведений о размере структуры типа А. Последующее определение в той же программе структурного типа А обязательно. Функция может возвращать структуру как результат:

struct help { char *name; int number; }; help func1 (void) ; // Прототип функции

Функция может возвращать указатель на структуру:

help *func2 (void) ; // Прототип функции

Функция может возвращать ссылку на структуру:

help& func3 (void) ; // Прототип функции

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

void func4 (help str) ; // Прямое использование

void func5 (help *pst); // С помощью указателя

void func6 (help& rst); // С помощью ссылки

Рассмотрим применение операции new к структурам. Операндом для операции new может быть структурный тип. В этом случае выделяется память для структуры использованного типа, и операция new возвращает указатель на выделенную память. Память может быть выделена и для массива структур, например, так:last = new record[9]; // Память для массива структур В этом случае операция new возвращает указатель на начало массива. Дальнейшие действия с элементами массива структур подчиняются правилам индексации и доступа к элементам структур. Например, разрешен такой оператор: last[0] .next = NULL;

Объединение разнотипных элементов

Объединения вводятся с помощью служебного слова union. Пусть дана структура

struct { long L; int i1, i2; char c[4]; } STR;

Каждый элемент структуры имеет свое место в памяти, и размещаются эти элементы последовательно. Определим очень похожее внешне на структуру STR объединение UNI:

union { long L ; int i1, i2; char c[4]; } UNI;

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

union имя_объединяющего_типа { элементы_объединения };

Пример объединяющего типа: union mixture { double d; long E[2]; int K[4]; };

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

mixture mA, mB[4]; // Объединение и массив объединений

mixture *pmix; // Указатель на объединение

mixture& rmix = mA; // Ссылка на объединение

Для обращения к элементу объединения можно использовать либо уточненное имя имя_объединения.имя_элемента, либо конструкцию, включающую указатель: указатель_на_объединение -> имя_элемента; (*указатель_на_объединение).имя_элемента, либо конструкцию, включающую ссылку ссылка_на_объединение. имя_элемента

mA.d = 64.8; mB[2]. E[1] = 10L;

pmix = &mB[0]; pmix -> E[0] = 66;

cin >> ( *pmix ).K[1]; cin >> rmix. E[0];

Заносить значения в участок памяти, выделенный для объединения, можно с помощью любого из его элементов. То же самое справедливо и относительно доступа к содержимому учаска памяти, выделенного для объединения. Основное достоинство объединения - возможность разных трактовок одного и того же содержимого (кода) участка памяти. Например, введя объединение union { float F; unsigned long K; } FK; можно занести в участок памяти, выделенный для объединения FK, вещественное число: FK.F = 3.141593; а затем рассматривать код его внутреннего представления как некоторое беззнаковое длинное целое: cout << FK.K; ( в данном случае будет выведено 10785330012).

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

union compound { long LONG;

int INT[2]; char CHAR[4]; };

compound mix1 = { 11111111 }; // правильно

compound mix2 = { ‘a’, ‘b’, ‘c’, ‘d’ }; // ошибка

union { char CHAR[4];

long LONG;

int INT[2] } mix = { ‘a’, ‘b’, ‘c’, ‘d’ }; // правильно

При определении объединений без явного указания имени объединяющего типа (как в последнем примере для объединения mix) разрешено не вводить даже имени объединения. В этом случае создается анонимное или безымянное объединение: union { int INT[5]; char CH[10] } = { 1,2,3,4,5 };. К элементам анонимного объединения можно обращаться как и к отдельным объектам, но при этом могут изменяться другие элементы объединения:

INT[0] = 10; // изменятся значения CH[0], CH[1]

CH[9] = ‘a’; // изменится значение INT[4]

Разрешено формировать массивы объединений и инициализировать их: compound mixture[ ] = { 1L, 2L, 3L, 4L };

Здесь для каждого элемента mixture[i] введенного массива из четырех объединений типа compound инициализация выполнена для первого компонента объединения, то есть начальное значение, явно получил каждый элемент mixture[i].LONG. Доступ к внутренним кодам этих значений возможен также через элементы mixture[i].INT[j] и mixture[i].CHAR[k].

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]