double arrow

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


Введите первое множество :

a

b

c

d

e

Введите второе множество :

e

f

g

h

i

Первое множество: a b c d e

Количество его элементов: 5

Второе множество:e f g h i

Объединение множеств: a b c d e f g h i

Разность множеств: a b c d

Пересечение множеств: e

Первое множество после удаления элемента 'a' : b c d e

Проверка на принадлежность элемента 'f' второму множеству:

Элемент принадлежит множеству

Проверка на равенство двух данных множеств:

Множества не равны

производные КЛАССЫ

Доступ к полям и функциям базового класса

#include <iostream.h> //библиотека потокового ввода-вывода

void f()

{

cout << “\nВнешняя функция”

}

struct Base1 //первый класс

{

void f() { cout << “\nФункция из Base1”;}

};

struct Base2 //второй класс

{

void f() { cout << “\nФункция из Base2;”}

};

struct Deriv: Base1, Base2 //класс, производный от двух данных классов

{

void f() {::f();} // вызов внешней функции

}

int main()

{

Deriv obj; //создаём объект класса Deriv

f();

obj.Base1::f();

obj.Base2::f();

obj.f();

return 0;

}

В результате работы программы будут выведены следующие строки:

Внешняя функция

Функция из Base1

Функция из Base2

Внешняя функция

Таблица 4.1

Доступ в базовом классе Атрибут доступа перед базовым классом Доступ в производном классе
struct class
public отсутствует public private
protected отсутствует public private
private отсутствует недоступны недоступны
public public public public
protected public protected protected
private public недоступны недоступны
public protected protected protected
protected protected protected protected
private protected недоступны недоступны
public private private private
protected private private private
private private недоступны недоступны

В таблице отражено преобразование статуса доступа как для классов, определенных с помощью ключевого слова struct, так и для классов, заданных с помощью class. Например:




Class A: protected B { };

Struct A: B { };

Класс дерева поиска

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

#include <stdio.h> //стандартная библиотека ввода-вывода

#include <conio.h> //библиотека консольного ввода-вывода

struct NODE //структура узла дерева

{

int info; //информационное поле

NODE *left, *right; //указатели на левое и правое поддеревья

};

class LIST //базовый класс списка

{

protected:

NODE *root;

public:

LIST() { root = NULL;}

};

class TREE: LIST //класс дерева поиска, производный

//от класса списка

{

public:

void insert(int x); //добавление элемента

void show(); //обход в симметричном порядке

};

NODE* insert(NODE* root, int x)

{

if (!root) //если дерево пусто, то

{

root = new NODE; //создаём новое дерево

root -> info = x; //заполняем информационную часть

root -> left = root -> right = NULL;

}

else

{

//дерево не пусто

//если значение добавляемого элемента меньше чем

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

//в левое поддерево



if (x < root -> info) root -> left = insert(root -> left, x);

//в противном случае его следует добавлять в правое поддерево

else root -> right = insert(root -> right, x);

}

return root;

};

void TREE :: insert(int x)

{

root = ::insert(root, x);

};

void display(NODE* p)

{

if(p)

{

display(p -> left); //переходим в левое поддерево

printf("\n%d", p -> info); //отображаем содержимое

//информационного поля

display(p -> right); //переходим в правое поддерево

}

};

void TREE :: show()

{

display(root);

};

int main()

{

TREE a; //создадим объект класса дерево

clrscr(); //очистим экран

//добавим в дерево произвольные элементы

a.insert(2);

a.insert(3);

a.insert(1);

a.insert(12);

a.insert(21);

a.insert(14);

a.insert(20);

a.insert(3);

printf ("Обход дерева в симметричном порядке:");

a.show(); //отобразим дерево на экране

getch(); //ожидание нажатия любой клавиши (пауза)

return 0;

}

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

Обход дерева в симметричном порядке:

Параметризованный связный список

Рассмотрим метод построения параметризованного списка с двойными связями. Список организовывается с помощью двух классов, первый из которых listob определяет природу элементов списка, а второй, dlist, реализует механизм списка с двойными связями. Первый из этих классов определяется следующим образом:

template <class DataT>

class listob // класс элемента списка

{

public:

DataT info; // информационная часть

listob <DataT> *next; // указатель на следующий элемент

listob <DataT> *prior; // указатель на предшествующий элемент

listob() // конструктор

{

info = 0; next = prior = NULL;

};

listob (DataT c) // конструктор

{

info = c; next = prior = NULL;

};



listob <DataT> *getnext() { return next;}

listob <DataT> *getprior() { return prior;}

void getinfo (DataT& c) { c = info; }

void change (DataT c) { info = c;} // изменение элемента

friend ostream &operator << (ostream &stream, listob <DataT> o);

friend ostream &operator << (ostream &stream, listob <DataT> *o);

friend istream &operator >> (istream &stream, listob <DataT> &o);

};

// перегрузка операции << для объекта listob

template <class DataT>

ostream &operator << (ostream &stream, listob <DataT> o)

{

stream << o.info << endl; return stream;

}

template <class DataT>

ostream &operator << (ostream &stream, listob <DataT> *o)

{

stream << o -> info << endl; return stream;

}

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

template <class DataT>

istream &operator >> (istream &stream, listob <DataT> &o)

{

cout << “Введите информацию: ”;

stream << o.info; return stream;

}

Механизм построения связного списка реализуется классом, приведенным ниже. Этот класс является производным от класса listob и оперирует с объектами класса listob.

template <class DataT> // параметризованный класс объекта списка

class dlist: public listob<DataT>

// класс списка - производный от класса узла

{

listob<DataT> *start, *end;

// указатели на первый и последний элементы

public:

dlist(){start=end=NULL;} // конструктор

~dlist(); // деструктор

void store(DataT c); // запись в список

void remove(listob<DataT> *ob); // удаление элемента

void frwdlist(); // чтение в прямом направлении

void bkwdlist(); // чтение в обратном направлении

listob<DataT> *find(DataT c); // поиск

listob<DataT> *getstart(){return start;} // начало поиска

listob<DataT> *getend(){return end;} // указатель на конец списка

}

Разработаем подпрограммы, выполняющие эти операции и тестовую программу.

// dlist.cpp - parametrised class of the double connected list

#include <conio.h>

#include <iostream.h>

#include <stdlib.h>

template <class DataT> class listob;

template <class DataT>

ostream &operator << (operator &stream, listob<DataT> o)

{

stream<<o.info<<endl; // вывод объекта

return stream;

}

/* template <class DataT>

ostream &operator<<(ostream &stream, listob<DataT> *o)

{

stream<<o->info<<endl; // вывод объекта по указателю

return stream;

}*/

/* template <class DataT>

istream &operator>>(istream &stream, listob<DataT> &o)

{

cout<<"Input data: ";

stream>>o.info; // ввод объекта

return stream;

}

*/

template <class DataT> class listob // класс узла

{

public:

DataT info; // информационная часть

Listob<DataT> *next, // указатель на следующий элемент

*prior; // указатель на предшествующий элемент

listob()

{

info=0; next = NULL; prior=NULL; // конструктор

}

listob(DataT c)

{

info=c; next=NULL; prior=NULL; // конструктор

}

listob<DataT> *getnext(){return next;}

// чтение адреса следующего элемента

listob<DataT> *getprior(){return prior;}

//чтение адреса предшествующего элемента

void getinfo(DataT &c){c=info;} // чтение информации в аргумент

void change(DataT c){info=c;} // изменение информации

friend ostream &operator<<(ostream &stream, listob<DataT> o);

// дружественные функции

//friend ostream &operator<<(ostream &stream, listob<DataT> *o);

// ввода - вывода

//friend istream &operator>>(istream &stream, listob<DataT> &o);

};

template <class DataT> // параметризованный класс объекта списка

class dlist: public listob<DataT>

// класс списка - производный от класса узла

{

listob<DataT> *start, *end;

// указатели на первый и последний элементы

public:

dlist(){start=end=NULL;} // конструктор

~dlist(); // деструктор

void store(DataT c); // запись в список

void remove(listob<DataT> *ob); // удаление элемента

void frwdlist(); // чтение в прямом направлении

void bkwdlist(); // чтение в обратном направлении

listob<DataT> *find(DataT c); // поиск

listob<DataT> *getstart(){return start;} // начало поиска

listob<DataT> *getend(){return end;} // указатель на конец списка

}

template <class DataT> dlist<DataT>::~dlist

{

listob<DataT> *p, *p1; // деструктор

p=start;

while(p)

{

p1=p->next; delete p; p=p1; // освобождение памяти, занятой

} // элементами списка

}

template <class DataT> void dlist<DataT>::store(DataT c)

{

listob<DataT> *p;

p= new listob<DataT>; // запись нового элемента

if(!p){cout<<"Error of memory allocation\n"; exit(1);}

p->info=c;

if(start==NULL)

// если список пуст, то создается список, состоящий из одного элемента

{

end=start=p;

}

else // иначе изменяем значения указателей

{

p->prior=end; end->next=p; end=p;

}

}

template <class DataT>

void dlist<DataT>::remove(listob<DataT> *ob)

// удаление элемента списка

{

if(ob->prior) // если не первый элемент

{

ob->prior->next=ob->next;

if(ob->next) // если не последний элемент

ob->next->prior=ob->prior;

else // иначе удаляется последний

end=ob->prior; // обновление указателя на конец списка

}

else // удаляется первый элемент списка, если список не пуст

{

if(ob->next)

{

ob->next->prior = NULL;

start=ob->next;

}

else // иначе, т.е. если список пуст,

start=end=NULL; // установить начало и конец на 0

}

}

template <class DataT>

void dlist<DataT>::frwdlist()

// вывод элементов списка в прямом направлении

{

listob<DataT> *temp;

temp=start;

while(temp)

{

cout<<temp->info<< " ";

temp = temp -> getnext();

}

cout<<endl;

}

template <class DataT>

void dlist<DataT>::bkwdlist()

// вывод элементов списка в обратном направлении

{

listob<DataT> *temp;

temp=end;

while(temp)

{

cout<<temp->info<< " ";

temp = temp -> getprior();

}

cout<<endl;

}

template <class DataT>

listob<DataT> *dlist<DataT>::find(DataT c)

// поиск объекта, содержащего информацию, совпадающую с указанной

{

listob<DataT> *temp;

temp=start;

while(temp)

{

if(c==temp->info) return temp; // совпадение найдено

temp = temp->getnext();

}

return NULL; // совпадение не найдено

}

main()

{

dlist<double> list; // демонстрация списка элементов типа double

double i;

listob<double> *p;

clrscr();

list.store(1); // запись элементов 1, 2, 3

list.store(2);

list.store(3);

cout<<"\nDirect list";

list.frwdlist(); // вывод в прямом направлении

cout<<"\nreverse list";

list.bkwdlist(); // вывод в обратном направлении

cout<<endl;

cout<<"Hand viewing of the list"; // ручной просмотр списка

p=list.getstart();

while(p)

{

p->getinfo(i); cout<<i<<" ";

p=p->getnext(); // следующий элемент

}

cout<<endl<<endl;

cout<<" find of 2\n";

p=list.find(2); // поиск элемента 2

if(p)

{

p->getinfo(i);

cout<<"we have find" <<i<<endl; // найден элемент i

}

cout<<endl;

p->getinfo(i);

cout<<"delete"<<i<<"\n";

list.remove(p); // удаление элемента

cout<<"list after deleting";

list.frwdlist(); // список после удаления

cout<<endl;

cout<<"insert the new 4"; // запись элемента 4

list.store(4);

cout<<"\nlist after insert";

list.frwdlist(); // вывод в прямом направлении

cout<<endl;

p=list.find(1); // поиск элемента 1

if(!p)

{

cout<<"Error. No such element\n"; return 1; // если не найден, выйти

}

p->getinfo(i); // чтение в i

cout<<"Change"<<i<<"to 5\n"; // вывод значения i

p->change(5); // изменение 1 на 5

cout<<"list after the change";

list.frwdlist(); // вывод в прямом направлении

cout<<"Reverse list":

list.bkwdlist(); // вывод в обратном направлении

cout<<endl;

getch();

return 0;

}

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

Список в прямом направлении: 1 2 3

Список в обратном направлении: 3 2 1

Ручной просмотр списка: 1 2 3

Поиск числа 2 в списке

Число 2 было найдено

Удаление числа 2 из списка

Список после удаления: 1 3

Запись нового элемента 4 в список

Список после вставки нового элемента: 1 3 4

Заменим 1 на 5

Список после замены: 5 3 4

Просмотр полученного списка в обратном порядке: 4 3 5

Множественное наследование

Пример. Пусть INTEGER – класс, объектами которого являются целые числа, POSITIVE – класс положительных целых чисел. Определим рациональную дробь как объект производного класса от этих двух классов. Пара, представляющая рациональную дробь, состоит из взаимно простых целых чисел.

#include <iostream.h> //библиотека потокового ввода-вывода

#include <process.h> //библиотека с прототипом функции exit

#include <conio.h> //библиотека консольного ввода-вывода

class INTEGER //класс целых чисел

{

public:

long NUM; //информационное поле

INTEGER (long Val): NUM(Val) {} //конструктор

};

class POSITIVE //класс положительных чисел

{

public:

unsigned long Den; // информационное поле

POSITIVE(unsigned long d) : Den(d) //конструктор

{

if(d==0) {cout << "Ошибка"; exit(1);}//ноль недопустим

}

};

class RATIONAL : public INTEGER, public POSITIVE

//класс дроби

{

//дружественная функция вывода дроби в некоторый поток

friend ostream &operator<<(ostream& stream, RATIONAL& o);

public:

RATIONAL(long v, unsigned long u=1): INTEGER(v), POSITIVE(u)

//конструктор

{

long w;

if (v==0) {u=1; return;}

if(v<0) {w = -v;}

else

{

w=v;

}

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

//взаимно простыми числами то следует найти наибольший

//общий делитель для числителя и знаменателя

while (w!=u)

{

if(w>u) w=w-u;

if(u>w) u=u-w;

}

//и следует сократить дробь

NUM = NUM/w;

Den = Den/w;

}

};

ostream& operator<<(ostream& stream, RATIONAL& o)

{

stream<<o.NUM<<"/"<<o.Den;

return stream;

}

main()

{

RATIONAL r1(10, 20), r2(-15, 10);

clrscr();

cout<<"Первая дробь (числитель равен 10, знаменатель равен 20): ";

cout<<r1<<"\n";

cout<<"Вторая дробь (числитель равен -15,знаменатель равен 10): ";

cout<<r2<<"\n";

getch();

}







Сейчас читают про: