Способы использования объектов


Дата добавления: 2014-01-11; просмотров: 3; лекция была полезна: 0 студентам(у); не полезна: 0 студентам(у).
Опубликованный материал нарушает авторские права? сообщите нам...

Эффективные типы, определяемые пользователем

 

Для типа, определяемого пользователем, характерен набор операций:

1) Конструктор, определяющий, как должны быть проинициализированы объекты данного типа.

2) Набор функций доступа (функций-селекторов). Эти функции имеют модификатор const, который указывает, что они не должны изменять состояние объектов, для которых они вызваны.

3) Набор функций-модификаторов. При их использовании не возникает необходимости разбираться в деталях представления или долго думать о смысле того или иного члена данных.

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

5) Перегруженные операторы – функции, обеспечивающие привычную (удобную) форму записи.

 

class complex{

public:

complex(double re=0,double im=0)

:_re(re),_im(im){}

double real()const{return _re;}

double imag()const{return _im;}

void add(complex);

private:

double _re,_im;

};

 

complex plus(complex a, complex b);

void print(complex a);

bool operator==(complex a, complex b);//перегруженный оператор

 

 

 

Объект может быть создан в качестве:

1) Именованного автоматического объекта, создаваемого каждый раз, когда встречается его объявление во время выполнения программы и уничтожаемого при каждом выходе из блока, в котором он объявлен.

void f(complex c){complex c1(2,3);}

2) Объекта в свободной памяти, создаваемого при помощи оператора new и уничтожаемого оператором delete.

complex *pc=new complex(2,3);

3) Нестатического члена-объекта, который создается и уничтожается тогда, когда создается и уничтожается содержащий его объект.

class X{

complex _c;

stack _s;

public:

X(complex &)

};

Аргументы конструкторов-членов указываются в списке инициализации членов в определении конструктора объемлющего класса.

X::X(complex &c)

:_c(c),_s(100)//список инициализации

{}

Конструкторы членов вызываются до вызова тела конструктора самого класса. Если объект-член не нуждается в аргументах, его можно не указывать в списке инициализации.

4) Элемента массива, который создается и уничтожается тогда, когда и создается и уничтожается массив, элементом которого он является.

complex cmas[10];

Вызывается конструктор по умолчанию для каждого элемента массива.

5) Локального статического объекта, который создается, когда его объявление встречается первый раз при выполнении программы и уничтожается один раз, при завершении программы.

{static complex c=sin(3);}

6) Глобального объекта, объекта в пространстве имен или статического объекта класса, которые создаются один раз «во время запуска программы» и уничтожаются один раз, при ее завершении.

complex c(1,0);

7) Временного объекта, который создается как часть вычисления выражения и уничтожается по завершении вычисления всего выражения.

k=plus(c1,complex(1,2)).imag(); return c1;

8) Объекта, размещенного в определенной области памяти.

9) Члена объединения union, который не может иметь ни конструктора, ни деструктора.

union economy{ rec c; double d};

 

Копирование объектов класса

Объекты можно копировать.

 

Существует 2 вида копирования объектов:

1) инициализация при помощи копирования

stack s2=s1;

2) присваивание

s2=s1;

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

Если это не то, что требуется для класса, можно реализовать подходящее поведение, написав для копирования собственную(ые) функцию(и). Для случая 1) это будет копирующий конструктор, а для случая 2) – копирующее присваивание.

class stack{

int cap;

int top;

char *s;//копирование по умолчанию создает

//стеки-сиамские близнецы

public:

stack(int capacity=10):cap(capacity),top(0),

s(new char[capacity]){}

~stack(){delete[] s;}

stack(const stack&);

stack& operator=(const stack&);//returns value for s1=s2=s3;

};

Использование:

stack a(100),c;a.push(‘a’);

stack b=a;с=a;

 

Для правильного копирования объектов данного класса копирующие функции нужно определить так:

 

#include <cstring>//for memcpy

stack::stack(const stack& st)

:cap(st.cap),top(st.top),s(new char[st.cap]){

//for(int i=0;i<cap;++i)s[i]=st.s[i];

memcpy(s,st.s,cap);

}

stack& stack::operator=(const stack&st){

if(this!=&st){

delete[] s;

 

s=new char[cap=st.cap];

//for(int i=0;i<cap;++i)s[i]=st.s[i];

memcpy(s,st.s,cap);

 

top=st.top;

}

return *this;

}

Копирующий конструктор и копирующее присваивание отличаются из-за того, что копирующий конструктор инициализирует «чистую» память, а копирующее присваивание должно правильно работать с уже созданным объектом (защита от присваивания самому себе, инициализация и копирование новых элементов).