Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование на C / C++ / Лекции по объектно-ориентированному программированию (С++).doc
Скачиваний:
111
Добавлен:
02.05.2014
Размер:
226.82 Кб
Скачать

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

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

Сlass TObject {---- // ----

---- // ----

public : TObject (TObject & );

---- // ----

}; либо

Сlass TObject {... ... ...

... ... ...

public : TObject (const TObject & (тип));

... ... ...

};

Class Tdefine {private : int TT;

public :

Tdefine (int r =1) {TT = r ;}

Tdefine (const Tdefine &NewObject)

{TT =NewObject . TT;}

void show_all ( )

{cout << ”значение ТТ = ” << TT <<endl;}

~ Tdefine ( ) { }

}; // конец определения класса

main ( )

{Tdefine copia1;

Tdefine copia2 (3 );

Tdefine copia3 = copia2;

copia1. show_all ( ); // 1

copia2. ------ // ------ // 3

copia3. ------ // ------ // 3

Выделенная строка означает не только обычное копирование. Знак “ = ” между объектами абстрактного типа означает предписание компилятору использовать конструктор копирования. Во многих компиляторах часто происходит автоматическая генерация этого конструктора, если он не был описан программистом.

Деструкторы – это функции – члены класса, которые обеспечивают действия, обратные действиям конструктора.

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

~ TObject ( )

{delete name;}

Иначе память будет считаться распределенной, и к ней нельзя будет обращаться.

Статические компоненты класса.

Есть возможность доступа всех созданных объектов конкретного класса к одной переменной (члену данному), содержимое которой хранится в одном месте. Для этого объявляют переменной:

static тип имя

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

тип имя_класса :: имя_переменной = нач.значение;

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

class Stat

{public : static int flag;

Stat ( ) {flag ++;}

int Ret_flg {return flag;}

};

main ( )

{stat S1, S2;

cout << ”количество вызовов конструктора : ”<<Stat :: flag <<endl;

stat S3;

cout << ”количество вызовов ... : ”<<S3. Ret_flg ( ); // 3

};

  1. Указатель this.

  2. Указатель на методы класса.

1. Каждый новый экземпляр класса получает свою собственную копию данных.

Функция – метод определяет, к какому объекту относится конкретный компонент класса.

# include <iostream.h>

# include <string.h>

class Stroka

{char *ss;

public : stroka (char*text) {ss =text;}

void write_ss ( ) {cout <<”string : “<<ss;endl;}

};

void main ( )

{stroka s1 (“Текст1”);

stroka s2 (“Текст2”);

s1.write_ss ( ); // Текст 1

s2.write_ss ( ); } // Текст 2

Для решения этой проблемы вводится неявный указатель this на объект класса. Функция write_ss ( ) в качестве неявного аргумента получает адрес одного из объектов s1 и s2.

Этот указатель (this) определен в каждой нестатической функции класса.

Надо проинициализировать:

имя_класса *this = адрес_объекта или

имя_класса *сonst this = адрес_объекта

Изменим наш пример.

public : ------ // ------ // ------

void write_ss ( ) {cout <<”string : “<<ss <<endl;}

void write_ss ( ) {cout <<”string : “<<this -> ss <<endl;}

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

Снимаем неоднозначность.

# include ------ // ------

# include ------ // ------

class Stroka

{char *name;

char *ss;

public : stroka (char *ss, char *text)

{name =ss; // неоднозначность присваивания полю name

ss = text; // кому присв. значение ?

void wr_ss ( )

{cout <<”string eto”<<name <<endl;

cout <<”string eto : ”<<ss <<endl;}

};

main ( )

{stroka s1 (“Первая строка”, ”text 1”);

stroka s2 (“Вторая строка”, ”text 2”);

s1.wr_ss ( );

s2.wr_ss ( );

}

*

# include

# include

class stroka

{char *name;

char *ss;

public : stroka (char *ss, char *text)

this → name = ss; // полю данных name присваивается значение конструктора stroka.

this → ss = text; // полю данных ss ------ // ------------ // ------------ // ------------ // ------------ // ------.

Можно использовать операцию расширения области видимости (::)

stroka :: name = ss;

stroka :: ss = text;

Использование this наиболее эффективно в функциях, которые явно работают с указателями на объект, для которых были вызваны эти функции.

2. Указатель на функции (методы класса).

Так как класс – новый тип данных, то для классов и для объектов типа “класс” может быть также определена операция получения адреса. То есть в программе мы можем использовать указатели на компоненты класса.

# include ------ // ------

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

class UK {public : int u1, u2;

UK (int value 1 =Ø, int value 2 = Ø)

{u1 = value 1;

u2 = value 2;

void print ( )

{cout << ”znachenie polya data = “ <<endl;

cout << “u1 = “ << u1 <<endl;

cout << “u2 = “ << u2 <<endl; }

}; // конец определения класса.

void set (UK& obj, int value)

{int UK :: * pos = &UK :: u2;

obj. *pos = value;} // pos- переменная, которая указывает на поле данных класса u2 типа int.

void main ( )

{UK ob1(1Ø); // присваиваем значение только u1, u2 =0 (cм. конструктор)

ob1. print ( );

set (ob1, 3Ø);

ob1. print ( );

}

Пример.

# include ------ // ------

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

class UK {------// ------

------// -----// ------ }

/ * void set ( ) */

void main ( )

{UK ob2 (1Ø, 3ØØ);

void (UK1 :: *func) ( ) = & UK :: print ( ); // объявление указателя на функцию-метод класса.

тип (*имя_указателя) ( ) = & имя_функции //

(ob2. *func) ( ); // косвенный вызов print

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