Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
шпоры печатать.docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
379.36 Кб
Скачать

29. Шаблоны классов. Конкретизация шаблона класса. Специализация шаблонов классов. Статические члены шаблонного класса.

элементы-функции класса. После определения шаблона класса вы можете предписать компилятору генерировать на его основе новый класс для конкретного типа или константы.

Синтаксис шаблона класса имеет следующий вид:

template <список_аргументов_шаблона>

class имя_класса

{

//тело класса

};

За ключевым словом template следуют один или несколько аргументов, заключенных в угловые скобки и отделяемых друг от друга запятыми. Каждый аргумент является либо именем типа, за которым следует идентификатор, либо ключевым словом class, за которым следует идентификатор, обозначающий параметризованный тип. Затем следует определение класса. Оно аналогично определению обычного класса, за исключением того, что использует список аргументов шаблона.

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

template <список_аргументов_шаблона> возвр_тип имя_класса <арг_шаблона> ::

имя_функции(параметры…)

{

// тело функции

}

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

Чаще всего шаблоны классов используют при описании контейнеров, чтобы затем конкретизировать их для хранения конкретных элементов. Например, в приведенном фрагменте кода на языке С++ объявляется параметризованный класс map(карта).

template <class Item, class Value, int Buckets>

Class map{

Public:

Virtual Boolean bind (const Item&, const Value&);

Virtual Boolean isBound (const Item&) const;

. . . };

Затем можно конкретизировать этот шаблон для отображения объектов класса Customer (Клиент) на объекты класса Order (Заказ):

map <Customer, Order, 3> m;

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

моделировать конкретизацию шаблона класса можно двумя способами. Во – первых, неявно, для чего требуется объявить класс, имя которого обеспечивает связывание. Во- вторых, можно явным образом определить зависимость со стереотипом bind (связывать), после которого перечисляются через запятую фактические параметры. Весь список аргументов берется в круглые скобки.

30.Ключевое слово typename. Недостатки шаблонов.

Ключевое слово typename

Это ключевое слово может применяться в двух случаях. Во-первых, им можно заменять ключевое слово class в списке параметров шаблона. Такое дополнение сделано в ANSI C++ потому, что ключевое слово class в списке параметров не вполне отражает положение дел;

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

template <class T> class SomeClass {...};

template <typename T> class SomeClass {...};

Во-вторых, typename необходимо, если шаблон определяет некоторые объекты еще не объявленных типов. Рассмотрите такой шаблон функции:

template <class T>

void Func(Т Sargi, typename T::Inner arg2)

{

typename T::Inner tiObj;

// Локальный объект

// типа Т::Inner.

// ...

31. Объектно-ориентированные приложения. Объектно-ориентированные стековые операции в С++. Объектно-ориентированный связанный список в С++. Динамическое распределение памяти: связанные списки. Особенности использования связанных списков

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

Связанный список — это набор структур, каждая из которых имеет некоторый элемент, или указатель, ссылающийся на другую структуру в этом списке. Указатель служит для связи между структурами. Эта концепция напоминает массив, однако она позволяет динамически увеличивать список. На рис. 14.1 показан простой связанный список для программы, работающей с реестром катеров фирмы Nineveh Boat Sales.

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

struct stboat {

char sztype[15];

char szmodel[15] ;

char sztitie[20] ;

char szcomment[80];

int iyear;

long int lmotor_hours;

float fretail;

float fwholesale;

struct stboat *nextboat;

} Nineveh, *firstboat,*currentboat;

Пользовательский структурный тип stboat называется ссылочной структурой, поскольку он имеет поле, содержащее адрес другой, аналогичной структуры. Указатель nextboat (следующий катер) хранит адрес следующей связанной структуры. Это позволяет указателю *nextboat первой структуры ссылаться на вторую структуру и так далее. Такова концепция связанного списка структур.

Особенности использования связанных списков

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

while (datain(&Nineveh) == 0) {

currentboat -> nextboat = (struct stboat *) new (struct stboat);

if (currentboat -> nextboat == NULL) return(l);

currentboat = currentboat -> nextboat;

*currentboat = Nineveh; }

Для того чтобы продемонстрировать передачу структуры в качестве параметра, в начале цикле while адрес структуры stboat, & Nineveh, передается в функцию datain(). Эта функция заносит в структуру действительные данные или возвращает значение 1, если пользователь нажал символ "Q", означающий окончание ввода. Если функция datain() не возвращает 1, то указателю currentboat->nextboat присваивается адрес динамически созданной структуры stboat. Обратим внимание на то, что выполняется приведение типа (struct stboat *) адреса, возвращаемого функцией new(), для того, чтобы согласовать его с типом принимающей переменной. Оператор if проверяет, был ли успешным вызов функции new (). (При ошибке new () возвращает значение null.)

Назначение переменной currentboat — хранить адрес последней действительной структуры stboat в списке; поэтому оператор, следующий за if, присваивает переменной currentboat адрес нового элемента списка, а именно — новый адрес nextboat.

Последний оператор в цикле копирует содержимое структуры Nineveh типа stboat в новую динамически созданную структуру, на которую ссылается указатель * currentboat. Указатель в последней структуре списка установлен на null — это означает конец связанного списка.

Во многих языках высокого уровня связанные списки позволяют создавать программы, весьма эффективно использующие память; зачастую эти программы — самые сложные для отладки.

32.Законченный проект программы со связанным списком и всеми (семью) характеристиками ООП. Создание родительского класса. Производные классы-потомки. Использование дружественного класса. Анализ законченной программы объектно-ориентированного связанного списка в С++.

// РОДИТЕЛЬСКИЙ КЛАСС

class NNR

{ friend class payroll_list;

protected:

char lstname[20]; char fstname[15]; char job_title[30]; char social_sec[12]; int year_hired; NNR *pointer; NNR *next_link;

public:

NNR(char *lname, char *fname, char *ss, char *job, int y_hired)

{ strcpy(lstname, lname); strcpy(fstname, fname);

strcpy(social_sec, ss); strcpy(job_title, job);

year_hired = y_hired; next_link = 0;}

В приведенной программе на основе общего родительского класса строятся несколько классов-потомков. Родительский класс для данного примера связанного списка называется NNR. Связанный список представляет собой базу данных, содержащую служебную информацию и платежные ведомости сотрудников фирмы. Родительский класс NNR хранит сведения, общие для всех порождаемых на его основе классов-потомков. В данном примере используется следующая общая информация: фамилия и имя сотрудника, должность, номер социальной страховки и стаж работы в фирме. Базовый класс NNR имеет три уровня защиты: public, рrotected и рrivate. В разделе рrotected этого класса содержится структура, хранящая данные, общие для всех производных классов. Раздел public (методы класса) показывает, какими способами можно обращаться к этой информации из функции main().Родительский класс и все производные классы используют дружественный класс, названный раyroll_list.

.Законченный проект программы со связанным списком и всеми (семью) характеристиками ООП. Производные классы-потомки.

// ПОДКЛАСС ИЛИ ПРОИЗВОДНЫЙ КЛАСС -Торговые агенты

class salespersons: public NNR

{ friend class payroll_list;

private:

float disk_sales; float comm_rate;

public:

salespersons(char *lname, char *fname, char *ss, char *job, int y_hired,

float d_sales, float c_rate): NNR(lname, fname, ss, job, y_hired)

{ disk_sales = d_sales;

comm_rate = c_rate; }

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

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

Теперь рассмотрим остальную часть описания класса-потомка:

void fill_saless(float d_sales)

{ disk_sales = d_sales;}

void fill_comm_rate(float c_rate)

{ comm_rate = c_rate; }

void add_info()

{ pointer = this; }

void send_info()

{ NNR:: send_info();

cout << "\n Sales (disk): " << disk_sales; // Объем продаж

cout << "\n Commission Rate: " << comm_rate; // Коммиссионные

}};

Для выделения памяти для каждого дополнительного элемента связанного списка в функции add_info() используется не операция динамического распределения памяти new, а указатель на объект this. Этому указателю присваивается адрес элемента класса NNR.

Законченный проект программы со связанным списком и всеми (семью) характеристиками ООП. Использование дружественного класса.

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

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

Для указания дружественных функций и классов используется ключевое слово friend.

Все методы дружественного класса, могут обращаться ко всем элементам класса, включая элементы, объявленные как private и protect.

Для объявления дружественного класса достаточно после ключевого слова friend записать имя класса:

class ИмяКласса {

...

friend class ИмяДружественногоКласса;

...

};

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

//==========================================================

// Класс point

class point

{

// ...

};

//==========================================================

// Класс line

class line

{

public:

// Класс point объявляется дружественным классу line

friend class point; };

37. Важнейшие библиотеки С и C++. Заголовочные файлы Microsoft С и C++. Стандартные функции общего назначения (stdlib.h). Преобразование данных. Преобразование числа с плавающей точкой в строку. Преобразование строки в длинное целое.

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

Содержание

bios.h*

Прерывания BIOS

conio.h

Ввод-вывод на консоль и в порты

ctype.h

Символьные функции

dos.h*

Прерывания DOS

io.h

Работа с файлами и ввод-вывод на нижнем уровне

math.h*

Математические функции

stdio.h

Потоковый ввод-вывод для С

stdlib.h*

Стандартные функции общего назначения

iostream.h

Потоковый ввод/вывод для С++

string.h*

Строковые функции

time.h*

Работа с датой и временем

заголовочные файлы — основной способ подключить к программе типы данных, структуры, прототипы функций, перечислимые типы, и макросы, используемые в другом модуле. Имеет по умолчанию расширение .h; иногда для заголовочных файлов языка C++ используют расширение .hpp. Чтобы избежать повторного включения одного и того же кода, используются директивы #ifndef, #define, #endif.

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

Если модуль правильно написан, с помощью условной компиляции можно отключить часть его функциональности.

Заголовочный файл позволяет задать то, что невозможно задать с помощью модулей — подстановки с помощью #define, директивы компилятора, незаконченные синтаксические конструкции…

Недостатки

Заголовочные файлы намного медленнее — чтобы откомпилировать 10 c-файлов, к каждому из которых подключён длинный h-файл, компилятору придётся пройти по заголовку 10 раз. Чтобы справиться с этой проблемой, во многих компиляторах используют предварительно откомпилированные заголовки.

Заголовочные файлы вместе с некоторыми объектами языка C++ (константы, inline-функции, шаблоны, static-переменные) образуют тяжеловесные конструкции.

Стандартные функции общего назначения (stdlib.h). Преобразование данных. Преобразование числа с плавающей точкой в строку. Преобразование строки в длинное целое.

Эти стандартные библиотечные функции и макросы составляют мощный набор средств преобразования данных, управления памятью и других, весьма разнообразных, действий. Наиболее часто встречаемые макросы и функции перечислены в таблице. Их объявления находятся в stdlib.h.

Макрос или функция

Выполняемое действие

_exit()

Завершение программы

_lrotl()

Циклический сдвиг беззнакового длинного целого влево

_lrotr()

Циклический сдвиг беззнакового длинного целого вправо

_rotl()

Циклический сдвиг беззнакового целого вправо

_rotr()

Циклический сдвиг беззнакового целого влево

abort()

Аварийное (ненормальное) завершение программы

abs()

Модуль (абсолютное значение) целого числа

atexit()

Регистрация функции, вызываемой при завершении программы

atof()

Преобразование строки в число с плавающей точкой

atoi()

Преобразование строки в целое

atol()

Преобразование строки в длинное целое

bsearch()

Бинарный поиск по массиву

calloc()

Отведение памяти

Преобразование данных

Первая важная группа функций, объявленных в stdlib.h, содержит функции преобразования. Основная задача этих функций — преобразование данных одного типа в данные другого типа. Например, функция atol() преобразует строку в длинное целое. Синтаксис этих функций задается следующими прототипами:

double atof(const char *s)

int atoi(const char *s)

long atol(const char *s)

char *ecvt(double value, int n, int * dec, int *sign)

char *fcvt (double value, int n, int * dec, int *sign)

Для всех этих функции *s является указателем на строку, value содержит преобразуемое значение, п указывает количество знаков в строке, в dec находится позиция десятичной точки относительно начала строки, sign содержит знак числа, *buf указывает на буфер символов, radix устанавливает основание системы счисления для преобразования, a endptr обычно равен нулю. Если же endptr содержит ненулевой адрес, то функция разместит по этому адресу символ, на котором закончился анализ строки.

Преобразование числа с плавающей точкой в строку

Функция fcvt() преобразует число с плавающей точкой в строку. Она также дает возможность получить информацию о знаке числа и о положении десятичной точки.

Преобразование строки в длинное целое

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

#include "stdafx.h"

#include <stdio.h>

#include <strstream>

#include <iostream>

using namespace std;

//#include <stdio.h>

//#include <stdlib.h>

main()

{ char *s="101101", *endptr; long long_number; long_number=strtol(s,&endptr,2);

// Двоичное число ... равно десятичному ...

printf("The binary value %s is equal to %ld decimal\n",s,long_number); return(0);}

38. Важнейшие библиотеки С и C++. Сортировка и поиск. Использование qsort()для сортировки целых чисел. Поиск целого числа в массиве.

Сортировка и поиск

Функция bsearch() используется для бинарного поиска в массиве. Функция qsort() производит быструю сортировку. Функция lfind() осуществляет линейный поиск по ключу в массиве последовательных записей, a lsearch() — линейный поиск в отсортированной или не отсортированной таблице.

void *bsearch(const void * key, const void *base,

size_t nelem, size_t width, int(*fcmp)(const void *,

const void *))

void qsort(void *base, size_t nelem, size_t width,

int(*fcmp)(const void *, const void *))

void *lfind(const void *key, const void *base,

size_t *num,size_t width, int(*fcmp)

(const void *, const void *))

void *lsearch(const void *key, const void *base,

size_t *num, size_t width, int(*fcmp)

(const void *, const void *))

Здесь key обозначает ключ поиска, *base — указатель на массив, в котором следует искать, nelem содержит количество элементов массива, a width — размер элемента в байтах. *fcmp — указатель на функцию, используемую для сравнения. В пит помещается количество элементов таблицы.

Использование qsort()для сортировки целых чисел

В Visual C++ есть функция qsort() для сортировки данных.

#include "stdafx.h"

#include <stdio.h>

#include <strstream>

#include <iostream>

using namespace std;

int int_comp(const void *i,const void *j);

int list[12]={95,53,71,86,11,28,34,53,10,11,74,-44};

main()

{ int i; qsort(list,12,sizeof(int),int_comp) ;

// Массив после сортировки

printf("The array after qsort:\n");

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

printf("%d ",list[i]) ;

printf("\n") ;

return (0) ;}

int int_comp(const void *i, const void *j)

{ return ((*(int *)i) - (*(int *)j));

}

Изначально массив list содержит целые числа со знаком. Функция qsort() упорядочивает их в том же массиве в порядке возрастания. В результате исходные числа оказываются отсортированными по возрастанию

39. Важнейшие библиотеки С и C++. Дополнительные функции. Использование генератора случайных чисел. Циклические сдвиги данных

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

Функция

Выполняемое действие

Завершение программы:

void abort(void)

Аварийно завершить программу с кодом возврата 3

int atexit(atexit_t func)

Выполнить функцию func перед завершением

void exit(int status)

Завершить программу с кодом status

void _exit(int status)

Немедленно завершить программу

Математические

int abs(int x)

Вычислить абсолютную величину х

int rand(void)

Выдать следующее случайное число

void srand(unsigned seed)

Инициализировать чисел генератор случайных

Циклический сдвиг

unsigned _rotl(unsigned val, int count)

Циклический сдвиг целого val влево

unsigned _rotr( unsigned val, int count)

Циклический сдвиг целого val вправо

Разное:

char *getenv(const char *name)

Прочитать переменную окружения

int putenv(const char *name)

Записать значение переменной окружения

void _swap(char *from, char *to, int nbytes)

Поменять местами заданное количество символов

В Visual C++ есть функция генерации случайного числа. Генератор случайных чисел может быть инициализирован функцией srand(). Функция инициализации принимает в качестве параметра целое число и инициализирует генератор случайных чисел.

#include <stdio.h>

using namespace std;

main()

{

int x;

srand(3);

for(x=0; x <8; x++)

printf("Trial #%d, random number=%d\n", x, rand());

return (0) ;

}

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

С и C++ предоставляют средства поразрядного циклического сдвига целых и длинных целых чисел вправо и влево.

#include <stdio.h>

using namespace std;

main()

{

unsigned int val=0x2345;

printf("rotate bits of %X to the left 2 bits and get %X\n", val, _rotl(val, 2));

printf("rotate bits of %X to the right 2 bits and get %X\n", val, _rotr(val, 2));

return (0) ;

}

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

40. Символьные функции (ctype.h). Проверка, является ли символ цифрой, буквой или символом ASCII. Проверка на управляющий символ, разделительный символ (пробел, табуляция, перевод строки) и знак препинания. Преобразования в код ASCII, к верхнему и нижнему регистрам.