Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Язык программирования Сpp 25.09.11 (2).doc
Скачиваний:
16
Добавлен:
19.08.2019
Размер:
10.09 Mб
Скачать

Класс Set

Set - это шаблон, определенный в заголовке sysset.h:

tempiate

class _declspec(delphireturn) Set;

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

Set a5et0f32;

typedef Set SetOfUppercase;

Перегруженный конструктор создает либо пустое множество, либо копию существующего множества того же типа.

Множества можно складывать, умножать (объединение и пересечение) и вычитать (пересечение c дополнением). Операции " и " соответственно вводят или удаляют элемент из множества. Эти же операции могут использоваться для извлечения и передачи множеств в поток (в виде последовательностей нулей и единиц), если перед sysset.h включается заголовок iostream или директива

#define VCL_IOSTREAM

Множества Set имеют два метода:

  • Sets _fastcall Clear (); Удаляет из множества все элементы.

  • boo1 _fastcall Contains(const T el) const; Возвращает true, если множество содержит указанный элемент.

/* Compile with bcc32 famille.cpp vcl.lib ole2w32.lib */

#include <vcl.h>

#include <stdio.h>

class Famille //Класс фамилия

{

private:

AnsiString FNames[10]; //Массив фамилий

AnsiString GetName(int Index); //прототипы функций

void SetName(int, AnsiString);

public:

//Создаем массив имен

__property AnsiString Names[int Index] = {read=GetName, write=SetName}; //массив читает номер и пишет имя

Famille(){} //пустой конструктор

~Famille(){}

};

AnsiString Famille::GetName(int i)

{return FNames[i];

}

void Famille::SetName(int i,const AnsiString s)

{FNames[i]=s;

}

int main()

{

Famille C;

C.Names[0]="Steve"; //calls Famille::SetName()

C.Names[1]="Amy";

C.Names[2]="Sarah";

C.Names[3]="Andrew";

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

{

//calls Famille::GetName()

puts(C.Names[i].c_str()); //вывод на экран

}

}

4.9. Перегрузка операторов

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

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

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

Пусть @ некоторый оператор языка, кроме следующих:

. – доступ к элементу класса (точка);

.* - доступ к указателю (точка со зведочкой);

:: - разрешение области видимости (двойное двоеточие);

?: - трехместная условная операция, (вопросительный знак с двоеточием, то же самое, что if - else);

# - указание препроцессору.

Тогда достаточно определить функцию с именем operator@ требуемым числом и типом аргументов, так, чтобы эта функция выполняла необходимые действия. То есть

Тип_результата operator @ (список_параметров)

{

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

}

Но в том случае, когда перегрузка производится в классе, т.е. функция-оператор является членом класса перегрузка имеет вид

Тип_результата имя_класса::operator @ (список_параметров)

{

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

}

То есть перегрузка оператора это построение функции с именем из специальных символов без передачи аргументов в явном виде. Перегрузка осуществляется с помощью кдючевого слова operator. Хотя функцию operator @ (список_параметров) можно использовать как обычную функцию. Оба способа будут показана в примере, который мы рассмотрим чуть позже.

При перегрузке операторов следует руководствоваться правилом:

  • Перегрузка не может изменять старшинство и ассоциативность операций;

  • Нельзя изменять число операндов операций;

  • операция присваивания = может быть использована с любым классом без явной перегрузки.

  • По крайней мере один аргумент перегруженного оператора должен принадлежать типу который является классом

  • Невозможно создать новый оператор. Все, что можно сделать, - это перегузить существующий оператор.

  • Нельзя изменять значение оператора по отношению к встроенным типам, т.е int, double, bul, и т.д.

  • Функция-операция (т.е. operator @ ) должна быть либо членом класса (структуры), либо воспринимать один или несколько аргументов, имеющих тип класса или структуры.

Рассмотрим пример перегрузки операторов в задаче сложения комплексных чисел. В программе перегружены операторы + и += . Причем показано, что перегрузка возможна для выбранных типов переменных.

//Сложение 2-х комплексных чисел

#include <iostream>

#include <windows>

using namespace std;

struct Complex{double real, imag;}; /* Объявление структуры в которой хранятся вещественная и мнимая части комлексного числа */

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

//Перегрузка оператора +

/*объявляем функцию аргументами которой являются адреса 2-х структур типа Complex*/

Complex operator+(Complex &a, Complex &b){

Complex c;

c.real=a.real+b.real;

c.imag=a.imag+b.imag;

return c;}

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

//Перегрузка унарного оператора += для комплексных чисел

void operator +=(Complex &a, Complex &b){

/*эта запись говорит о том, что если встретится инструкция a+=b то нужно сделать следующее */

a.real=a.real+b.real;

a.imag=a.imag+b.imag;

}

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

/* Перегрузка унарного оператора += для действительных чисел типа double */

void operator +=(Complex &a, double b){

a.real +=b;

}

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

//определение функции для вывода комплексных чисел

void showComplex (const Complex &x){

if(x.imag>=0)cout<<x.real<<"+j"<<x.imag<<endl;

else cout<<x.real<<"-j"<<-x.imag<<endl;

}

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

int main(){

Complex x,y,z1,z2;

x.real=20; x.imag=40;

y.real=30; y.imag=50;

SetConsoleOutputCP(1251);

cout<<"Первое число:"; showComplex(x); //Вывод числа x

cout<<"Второе число:"; showComplex(y); //Вывод числа y

z1=operator+(x,y); //здесь перегрузка используется как функция

cout<<"Определение суммы с помощью функции:"; showComplex(z1);

z2=x+y; //перегруженный оператор используется в операции

cout<<"Определение суммы с помошью оператора:"; showComplex(z2);

z1 +=x; //то же, что operator+=(z1,x);

cout<<"Если добавить первое число к сумме, то получится:"; showComplex(z1);

z2 +=30.0; //то же, что operator+=(z2,30.0);

cout<<"Если добавить число 30 к сумме, то получится:"; showComplex(z2);

int i; cin>>i;

return 0;

}

Вот результат работы программы

В этой программе одна и таже функция перегрузки

Complex operator+(const Complex &a,const Complex &b)

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

z1=operator+(x,y);

Второй раз как перегруженный оператор

z2=x+y;

Вызов функции в качестве оператора сложения не вызывает никаких трудностей. Напротив, второй вариант, вероятно, не совсем понятен. Сделаем некоторые пояснения. Встретив знак + для небазового типа Complex компилятор проверяет, не является ли этот оператор перегруженным. С этой целью он ищет функцию, у которой имя содержит ключевое слово operator и указанный знак операции. Если эта функция найдена, то он проверяет соответствие её параметров числу и типам операндов. После этого обеспечивает выполнение написанного кода.

В качестве примера перегрузки в классе рассмотрим перегрузку опрератора массива или, лучше сказать, оператора работы с индексами [ ]. В качестве примера рассмотрим класс предназначенный для хранения строки и числа. Чтобы привлечь ваше внимание пусть это будет имя шпиона и его поядковый идентификационный номер (ПИН). Программа подготовлена для случая когда агент по имени Bond забыл свой номер. Введя свое имя, а точнее фамилию он узнает номер.

#include <iostream>

#include <string>

using namespace std;

const int MAX_LEN=100;

/* Класс для хранения имени шпиона и его ПИНа

* имя хранится в массиве strcpy, а ПИН в переменной типа

* int decoderKey */

class SecretInfo{

int decoderKey;

char codeName[MAX_LEN];

public:

SecretInfo(char *spyName, int spyKey); /*Объявляем конструктор

* с двумя аргументами */

int operator [](const char *spyName); //Перегрузка [] вклассе

}; //Конец класса

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

/* Данный конструктор осуществляет перезапись аргументов

* в переменные объявленные в классе */

SecretInfo::SecretInfo(char *spyName, int spyKey){

strcpy(codeName, spyName); /* встроенная функция strcpy

* копирует вторую строку в первую */

decoderKey=spyKey;

}

/* Определение перегружаемого оператора */

int SecretInfo::operator[](const char *spyName){

if(!strcmp(codeName, spyName)) /* strcmp функция сравнения строк

* возвращает 0 если строки совпадают

* следует напомнить, что в языке С

* вместо false используется ноль*/

return decoderKey;

else

return 0;

} //конец функции-оператора

/*теперь оператор [] означает ПИН агента*/

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

int main(void){

SecretInfo agent("Bond",7);

char temp[MAX_LEN];

cout<<"Input Your code name:";

cin>>temp;

if(agent[temp])

cout<<"Your Kode Name"<<agent.operator [](temp);

else

cout<<"Sorry Bond! False Name Code"<<endl;

char z;

cin>>z;

return 0;

}

Пример

#include <iostream>

#include <vector>

#include <string>

#include <cstdlib>

#define EOS -1 //Конец строки(возвращаеться функцией get_word)

using namespace std;

class dict_el{ //Элемент словаря (слово и его позиции)

public:

dict_el():Word(""){}; //Конструсторы

dict_el(string wd):Word(wd){};

~dict_el(){}; //Деструктор

void add_pos(const int i){ //Добавить позицию

this->pos.push_back(i);

};

bool operator==(const string& str){

/* сравнение со строкой для алгоритма find */

return (this->Word == str)? true:false;

}

friend ostream& operator<<(ostream& cout, dict_el& rhs);

/*Вывод слова и его позиций */

private:

string Word; //Хранимое слово

vector<int> pos; //Позиции для хранимого слова

};

ostream& operator<<(ostream& cout, dict_el& rhs){

/*Вывод слова и его позиций*/

cout << rhs.Word << ": ";

vector<int>::iterator i;

for (i = rhs.pos.begin(); i != rhs.pos.end(); ++i)

cout << *i << " "; //Выводит слово : и его позиции

return cout;

}

int get_word(string& str,string& res){ //получить следующее слово

static int current=0; //текущая позиция

int i;

while(isspace(str[current]) ) {

++current; //пропустить все знаки пробел,

} //переход строки и т.д.

if (str[current] == '\0') return EOS; //достигнут конец строки

i = current; //начало нового слова

res="";

while(!isspace(str[current]) && str[current] != '\0'){//считывать слово до конца

res+=tolower(str[current++]); //и записывать его в res

}

return i; //вернуть позицию слова

}

void parse_str(string& str, vector<dict_el>& dict){

/* Разбор строки и формирование словаря */

string temp; //следующее слово

int position; // и его позиция

vector<dict_el>::iterator i;

while((position=get_word(str,temp)) != EOS){ /*Пока не дошли до конца строки получить следующее слово */

i=find(dict.begin(),dict.end(),temp); //искать это слово в словаре

if (i == dict.end()){ //если такого слова нет

dict_el A(temp); //создать его

A.add_pos(position); //ввести первую позицию

dict.push_back(A); //и добать в словарь

}

else{ //если слово уже есть

(*i).add_pos(position); //добавть к нему новую позицию

}

}

}

//Начало программы int main(){ string str="Testing my Testing my program\0"; //Строка для разбора

vector<dict_el> dict; //Словарь

parse_str(str,dict); //Создать словарь

vector<dict_el>::iterator i;

for(i = dict.begin(); i != dict.end(); ++i){ //Вывести словарь

cout << *i << endl;

}

return 0;

}