Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lutsik_Yu_A_Obektno_orientir_programmir_na_yaz.pdf
Скачиваний:
63
Добавлен:
11.05.2015
Размер:
4.33 Mб
Скачать

void tree::see(node *u) // функция рекурсивного вывода бинарного дерева

{if(u)

{cout<<"узел содержит: "<<u->inf<<" число встреч "<<u->n<<endl;

if (u->l) see(u->l);

// вывод левой ветви дерева

 

if (u->r) see(u->r);

// вывод правой ветви дерева

 

}

 

 

}

 

 

int main()

 

 

{ tree t;

 

Р

int i;

 

 

 

while(1)

 

 

{ cout<<"вид операции: 1 − создать дерево"<<endl;

 

 

 

cout<<"

 

2 − рекурсивный вывод содержимого дерева"<<endl;

 

 

cout<<"

 

3 − нерекурсивный вывод содержимого дерева"<<endl;

 

 

cout<<"

 

4 − добавление элементов в деревоИ"<<endl;

 

 

cout<<"

 

5 − удаление любого элемента из дерева"<<endl;

 

 

cout<<"

 

6 − выход"<<endl;

 

У

 

 

 

Г

 

 

cin>>i;

 

 

 

 

 

 

 

switch(i)

 

 

 

 

 

Б

 

 

 

{ case 1: t.sozd(); break;

 

 

 

 

 

case 2: t.see(t.root());

break;

 

 

 

 

case 6: return;

 

 

 

а

 

 

 

}

 

 

 

к

 

 

 

 

return 0;

 

 

 

 

 

 

}

 

 

е

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

При небольш й м дификации в функции main() можно создать несколько

объектов класса tree

т

 

 

 

 

, например, используя указатель на объект класса tree, вы-

 

 

о

 

 

 

 

 

зывать методы к асса для работы с каждым из созданных объектов (бинарных

деревьев). Это преобразование предлагается выполнить самостоятельно.

 

 

и

 

 

 

 

 

 

 

3.3.лКонструктор копирования

 

 

Нео ходимость использования конструктора копирования вызвана тем,

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

31

рый в качестве единственного параметра получает ссылку на объект класса. Общий вид конструктора копирования имеет следующий вид:

имя_класса (const имя_класса & );

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

#include <iostream>

 

 

using namespace std;

 

Р

#include <stdlib.h>

 

class cls

 

 

 

{ char *str;

 

 

 

И

int dl;

 

 

 

// . . .

другие данные класса

 

У

public:

 

 

Г

 

 

Б

 

cls ();

//

конструктор по умолчанию

 

 

 

cls(cls &);

//

копирующий конструктор

 

 

~cls();

//

деструктор

 

 

 

// . . . другие методы класса

};

 

 

 

 

ка

cls::cls ()

 

 

 

{ dl=10;

 

 

 

е

 

str=new char[dl];

 

}

 

 

 

 

т

cls::cls(cls & obj1)

о

 

// к пирующий конструктор из obj1 в obj

{ dl=obj1.dl;

 

и

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

 

 

 

 

str=new char[dl];

 

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

 

 

л

 

// копирование строки

}

strcpy(str,obj1.str);

 

 

 

 

 

 

cls::~cls()

 

 

 

 

 

и

 

 

 

 

{ delete [] str;

 

 

 

}

cout<<"бдеструктор"<<endl;

 

 

 

 

 

void fun(cls obj1)

 

 

 

Б{ // код функции

 

 

 

cout<<" выполняется функция "<<endl;

}

void main(void)

{cls obj;

//. . .

32

fun(obj); // . . .

}

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

3.4.Конструктор explicit ГУИР

ВС++ компилятор для конструктора с одним аргументом может автома- тически выполнять неявные преобразованияБ. В результате этого тип, получае- мый конструктором, преобразуется в объект класса, для которого определен данный конструктор. акского выделения памяти). Таким образом, даже если в классе не используются

 

{ int size;

 

//

 

 

е

 

 

 

размерность массива

 

 

int *ms;

 

//

 

указа ль на массив

 

public:

о

 

 

 

array(int = 1);

т

 

 

и

 

 

 

~array();

 

 

 

 

friend void print(const array&);

 

};

л

 

 

 

 

 

 

 

 

 

 

 

 

 

array::array(int kl) : size(kl)

 

{ cout<<"работает конструктор"<<endl;

и

 

 

 

 

// выделение памяти для массива

 

ms=new int[size];

 

Б

бfor(int i=0; i<size; i++) ms[i]=0; // инициализация

}

 

 

 

 

 

 

array::~array()

 

 

 

 

{ cout<<"работает деструктор"<<endl;

delete [] ms;

}

void print(const array& obj)

{ cout<<"выводится массив размерностью"<<obj.size<<endl; for(int i=0; i<obj.size; i++)

33

cout<<obj.ms[i];

cout<<endl;

}

 

 

 

 

 

 

 

 

void main()

 

 

 

 

 

 

 

 

{ array obj(10);

 

 

 

 

 

 

 

print(obj);

// вывод содержимого объекта obj

 

 

 

 

print(5);

// преобразование 5 в array и вывод

 

 

 

 

}

 

 

 

 

 

 

 

Р

В результате выполнения программы получим:

 

 

 

работает конструктор

 

 

 

 

 

 

выводится массив размерностью 10

 

 

 

 

0 0 0 0 0 0 0 0 0 0

 

 

 

 

 

 

работает конструктор

 

 

 

 

 

 

 

 

 

 

 

И

выводится массив размерностью 5

 

 

 

0 0 0 0 0

 

 

 

 

 

 

 

 

 

 

 

У

 

работает деструктор

 

 

 

 

 

работает деструктор

 

 

 

 

 

 

 

 

Г

 

 

В данном примере в инструкции:

 

 

 

Б

 

 

 

array obj(10);

 

 

 

 

 

 

 

 

 

 

 

 

 

определяется объект obj и для его создания (и иници лизации) вызывается кон-

структор array(int). Далее в инструкции:

таobj

 

 

 

 

print(obj);

 

 

е

 

 

 

 

// вывод содержимого объ

 

 

 

 

выводится содержимое объекта obj, используякfriend-функцию print(). При вы-

полнении инструкции:

т

 

 

 

 

 

print(5);

 

о

 

 

 

 

 

 

// преобраз вание 5 в array и вывод

 

 

 

 

компилятором не находится функция print(int) и выполняется проверка на на- личие в классе array конструкт ра, способного выполнить преобразование в

объект класса array. Так как в классе array имеется конструктор array(int), а точ-

 

л

нее, просто конструктор с одн м параметром, то такое преобразование возмож-

но (создается временныйиобъект, содержащий массив из пяти чисел).

В некоторых с учаях такие преобразования являются нежелательными

и

 

или, возможно, приводящими к ошибке. В С++ имеется ключевое слово explicit

Б

 

для подавленбя неявных преобразований. Конструктор, объявленный как explicit:

explicit array(int = 1);

не может быть использован для неявного преобразования. В этом случае ком- пилятором (в частности Microosft C++) будет выдано сообщение об ошибке:

Compiling...

error C2664: 'print' : cannot convert parameter 1 from 'const int' to 'const class array &' Reason: cannot convert from 'const int' to 'const class array'

No constructor could take the source type, or constructor overload resolution was ambiguous

34

Если необходимо при использовании explicit-конструктора все же создать массив и передать его в функцию print, то надо использовать инструкцию

print(array(5));

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

 

class array

 

 

 

 

//

класс-массив целых чисел

 

{ public:

 

 

 

 

 

 

 

 

 

 

 

class array_size

 

 

//

класс-размер массива

 

 

{ public:

 

 

 

 

 

 

 

 

Р

 

 

 

array_size(int _kl):kl(_kl){}

 

У

 

 

 

int size() const { return kl;}

Г

И

 

 

private:

 

 

 

 

 

 

 

};

int kl;

 

 

 

 

 

Б

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

array(int n,int m)

 

 

а

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

{ this->n=n;

 

 

к

 

 

 

 

 

 

ms=new int[this->n];

 

 

 

 

 

 

 

 

for(int i=0;i<this->n;i++) ms[i]=m;

 

 

 

 

 

 

 

 

 

 

 

е

 

 

 

 

 

 

 

 

 

 

 

т

 

 

 

 

 

 

 

 

array(array_size

size)

 

 

 

 

 

 

 

 

{ n=_size.size();

 

 

 

 

 

 

 

 

 

}

ms=new int[n];

 

 

 

 

 

 

 

 

 

 

и

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

};

~array(){ delete [] ms;}

 

 

 

 

 

 

 

л

о

 

 

 

 

 

 

 

 

 

private:

 

 

 

 

 

 

 

 

 

int n;

 

 

 

 

 

 

 

 

 

 

б

 

 

 

 

 

 

 

 

 

 

 

 

int *ms;

 

 

 

 

 

 

 

 

 

и

 

 

 

 

 

 

 

 

 

 

 

Б

main()

 

 

 

 

 

 

 

 

 

 

{

array a(1);

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

. . .

};

Компилятор для объекта a генерирует вызов конструктора array(int). Но такого конструктора не существует. Компиляторы могут преобразовать аргу- мент типа int во временный объект array_size, поскольку в классе array_size име- ется конструктор с одним параметром. Это обеспечивает успешное создание объекта.

35

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