Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

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

Поиск

Также возможна и перегрузка оператора ввода из потока»,

с ее помощью можно научить C++ читать из потока объекты класса.

В листинге 15.9 к возможностям программы-примера POINTOUT.CPP из предыдуще­го раздела добавляются возможности чтения из потока.

Листинг 15.9. POINTIN.CPP

(классы и потоки ввода)

«include <iostream.h>

class TPoint {

private:

int x, y;

public:

TPoint() { x = у = 0; }

TPoint(int xx, int yy) { x = xx; у = yy; }

void PutX(int xx) { x = xx; }

void PutY(int yy) { у = yy; }

int GetX(void) { return x; }

int GetY(void) { return y; }

friend ostream& operator<<(ostream& os, TPoint &p);

// дружественная функция-член

ввода из потока operator»()

friend istream& operator>>(istream& is, TPoint &p);

};
main()

TPoint p;

cout «p «'\n';

p.PutX(100);

p.PutY(200);

cout «p «'\n';

cout << "\nEnter x and у values: ";

cin» p;

cout << "\nYou entered: "«p; return 0; }

ostream& operator«(ostream& os, TPoint &p) {

os «"x == " «p.x «", у == " «p.у;

return os;}

// читаются значения для х и у с помощью

// ссылки is на istream.

// Функция возвращает ссылку is, т.о.

// можно вводить несколько значений

// в одном операторе ввода.

istream& operator>>(istream& is, TPoint &p){

is» p.x» p.y;

return is;}

В строке 14 для класса TPoint объявляется дружественная функция-член ввода из потока operator»(), аналогичная функции перегрузки оператора вывода в поток, приведенной в предыдущем разделе, только вме­сто ostream используется istream.

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

При запуске программы на выполнение запрашиваются два значения для х и у. Введите два целочислен­ных значения, разделенных пробелом. Оператор ввода из потока в строке 26 сохранит оба введенных вами значения в объекте класса, которые затем отобразятся в строке 27.

Шаблоны

Подобно тому как класс представляет собой схематическое описание построения объекта, так и

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

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

Шаблонные функции

Шаблоны функций описывают общие свойства функций, подобно рецепту приготовления пирожного.

Шаб­лоны функций, обычно объявляемые в заголовочном файле, имеют следующий общий вид:

 

template<class T> void f(T param){

// Тело функции}

//Т — опреде­ляемое пользователем

//имя функции

 

Шаблонная функция начинается строкой template<class Т>, указывающей компилятору, что Т — опреде­ляемое пользователем имя функции.

(Вы можете заменить Т на любое другое имя, если захотите.)

Необхо­дим, по крайней мере, один параметр Т для передачи функции данных для обработки. Можно также за­дать указатель

(Т* param)

или ссылку

(Т& param).

 

Функция может объявлять несколько параметров и воз­вращать значение типа Т:

template<class T> T f(int а, Т b)

{

// Тело функции}

//ф-ция f() возвращает значения типа //Т и имеет два параметра — целое с //именем а и неопределенный объект //Т с именем b.

 

В этой версии шаблонная функция f() возвращает значения типа Т и имеет два параметра — целое с именем а и неопределенный объект Т с именем Ь.

 

Пользователи шаблона укажут действительный тип данных для Т.

 

На­пример, в программе можно задать следующий прототип:

double f(int a, double b);

//Если это обычная функция, мы //должны обеспечить ее реализацию, //т.к. f() — шаблонная функция, //компилятор реализует код функции, //заменив Т в данном случае на // double.

ПРИМЕР 4.10: … как с помощью шаблонов можно уменьшить размер и слож­ность программ, предоставив компилятору реализацию обобщенных функций.

Листинг 4.10. MINMAX.H

(шаблоны функций min и max)

// minmax.h -- Шаблоны функций min и max

#ifndef MINMAX_H

#define MINMAX_H 1

// Предотвращение повторных include

//Т заявлен неопределенным типом,

// объект которого возвращает

//шаблонная функция mах()

template<class T> T max(T a, T b) {

//схема для реальных операторов, которые

//будут сгенерированы позже

if (a > b)

return a;

Else

return b;}

template<class T> T min(T a, T b) {

if (a < b)

return a;

Else

return b;}

#endif // _MINMAX_H

Рассмотрим подробнее строку 6. В ней Т заявлен неопределенным типом, объект которого возвращает шаб­лонная функция mахО. Кроме того, функции mах() необходимы два аргумента типа Т. Операторы в функции, приведенные в строках 8-11 — схема для реальных операторов, которые будут сгенерированы позже, когда будет задан действительный тип Т. Шаблон функции min() объявляется аналогичным образом.

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

В листинге 4.11 приводится пример такой программы.

Листинг 4.11. FTEMPLAT.CPP (использование шаблонов функций)

//4_11.cpp

//использование шаблонов функций)

#include <iostream.h>

#include <conio.h>

#include "minmax.h"

int max(int a, int b);

// три прототипа шаблонной

//перегруженной ф-ции mах()

double max(double a, double b);

char max(char a, char b);

Main()

{int i1 = 100, i2 = 200;

double d1 = 3.14159, d2 = 9.87654;

char c1 = 'A', c2 = 'z';

cout << "max(i1,i2) =="<< max(i1, i2) << '\n';

cout << "max(d1,d2) =="<< max(d1, d2)<<'\n';

cout << "max(c1,c2) =="<< max(c1,c2) << '\n';

//Все функции mах() возвращают //объ­екты различных типов данных и //требуют два аргумента этих же //типов.

getch();

return 0;

}

В строках 4-6 объявляются три прототипа шаблонной функции mах(). Эти строки дают компилятору необхо­димую информацию для реализации трех перегруженных функций mахО.

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

 

Можно использовать более одного неопределенного типа. Для объявления mах() с двумя различными неопределенными типами можно написать:

template<class T1, class T2> T1 max(T1 a, T2 b)

//функция mах() будет возвращать \\значение типа Т1, и ей необходимы \\два аргумента: один -1 типа Т1, \\другой — типа Т2.

 

Шаблонные классы

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

Шаблон класса обеспечивает скелет обобщенного класса для его последующей реализации.

Как и шаблоны функций, шаблоны классов чаще всего объявляются в заголовочных файлах.

 

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

template<class T> class TDatabase {

// Закрытые, защищенные и //открытые члены класса

}

где T - неопределенный тип, задаваемый пользователем шаблона. (Можно заменить Т на любой другой идентификатор, если захотите.) Т можно впоследствии заменить любым встроенным типом, другим классом, указателем и т.д.

TDatabase — имя шаблонного класса.

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

template<class T>

class TAClass {

. }

Можно также указать несколько неопределенных типов:

template<class T1, class T2, class T3> class TAnotherClass {

}

 

ПРИМЕР:4.12: демонстрация объяв­ления шаблона класса, реализующего базу данных с небольшим числом записей.

 

Листинг 4.12. DB.H (шаблон класса TDatabase)

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

 

// db.h -- Объявление шаблонного класса TDatabase

#ifndef __DB_H

#define __DB_H 1

// Предотвращение нескольких

template <class T>

class TDatabase {

private:

T *rp; //указ-тель на записи

Int num; //число записей

public:

TDatabase(int n)

//\\выделяет память для массива //объектов Т

{ rp = new T[num = n]; }

~TDatabase()

{ delete[] rp; }

void DoNot(void);

T &GetRecord(int recnum);

};

template<class T>

void TDatabase<T>::DoNot(void)

{}

template<class T>

// возвращает ссылку на объект типа //Т, идентифицируемый номером //записи recnum.

T TDatabase<T>::GetRecord(int recnum)

{

T *crp = rp; // Указатель на текущую запись = указатель на записи

if (0 <= recnum && recnum < num)

while (recnum-- > 0)

crp++;

return *crp;

}

//#endif //__DB_H

 

Например, в объявлении класса TDatabase в строке 9 объявляется указатель на Т с именем гр:

T *rp;

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

конструктор TDatabase в строках 12-13 выделяет память для массива объектов Т, присваивая адрес массива указателю гр и заодно устанавливая член num равным требуемому числу записей.

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

В строке 15 этот массив удаляется с помощью оператора специального вида delete[] с целью обеспечения вызова деструктора для массива, содержащего объекты класса.

В строке 17 объявляется функция-член GetRecordO, возвращающая ссылку на объект типа Т, идентифицируемый номером записи recnum. Это еще один вид обобщенной операции, не требующей знания определенного типа Т.

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

template<class T>

void TDatabase<T>::DoNot(void)

{

Заголовок функции-члена предварен фразой template<class T>. Затем следует тип возвращаемого функци-1 ей значения (void), имя класса (TDatabase<T>) и оператор разрешения области видимости (::). Последним! идет объявление самой функции (DoNothing(void)) и тело (пустое, в данном случае). Используйте этот при­мер как образец для написания ваших собственных функций-членов шаблонных классов.

В строках 25-33 демонстрируется более сложный пример функции-члена шаблонного класса вместе с опера-1 торами, реализующими действия функции. Функция GetRecordO возвращает ссылку на объект типа Т. Внутри функции указатель сгр типа Т присваивается указателю того же типа с именем гр. Иными словами, указатель сгр ссылаетсяна первую запись, сохраненную в объекте класса TDatabase. В строке 29 проверяется, соответствует ли параметр recnum допустимому диапазону значений. Если да, цикл while в строках 30-31 декрементирует пара­метр recnum до нуля и одновременно передвигает указатель сгр на одну запись в базе данных.

Обратите внимание на строку 31. Инкрементирование указателя р с помощью выражения р++ сдвигает I указатель на число байтов объекта, на который ссылается р. В классе Database даже несмотря на то, что тип объекта, на который ссылается сгр, не известен, вполне приемлемо выражение сгр++. Позже, когда будет за­дан действительный тип для шаблона класса, компилятор сможет сгенерировать соответствующие инструкции для увеличения указателя сгр на величину sizeof(T). Без шаблонных классов подобные обобщенные операто­ры было бы не так-то легко написать.

В строке 32 возвращается разыменованное значение указателя сгр — другими словами, ссылка на любой] объект, адресуемый сгр. Это завершает объявление шаблона класса, в котором не делается никаких предположений о том, какого типа данные в нем запоминаются.

Следующий шаг — использование шаблона для создания объекта класса базы данных, способного запом­нить некоторое число записей. В листинге 4.13 демонстрируется работа шаблона класса TDatabase.

 

Листинг 4.13. CTEMPLAT.CPP (использование шаблонов класса)

//4_13.cpp

#include <conio.h>

#include <iostream.h>

#include <string.h>

#include "db.h"

class TRecord { private:

char name[41];

public:

TRecord ()

{ name[0] = 0; }

TRecord(const char *s)

{ Assign(s); }

void Assign(const char *s)

{ strncpy(name, s, 40); }

char *GetName(void)

{ return name; }

};//class

int main() {



Поделиться:


Последнее изменение этой страницы: 2016-08-01; просмотров: 282; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.15.26.184 (0.007 с.)