Void main ( )

Void display()

Double X

public:

pair (int n, double x)

{ N=n; X= x; }

friend pair & operator ++ (pair &); // префиксная

friend pair & operator++ (pair&, int); // постфиксная

pair& operator- - () // префиксная

{ N= N-1; X - = 1.0;

return * this; }

pair& operator- - (int k) // постфиксная

{ N= N-1+k; X - = 1.0 +k;

return * this;}

{ cout<< “\n N = “ <<N <<” X= “ << X; }

};

pair & operator ++ (pair & P) // префиксная

{ P. N + = 1; P.X +=1.0;

return P; }

pair & operator ++ (pair & P, int k) // постфиксная

{ P. N + = 1+k; P.X +=1.0 +k;

return P; }

{ pair A (9, 19.0); A.display();

++A; A.display ();

- - A; A.display ();

A++; A.display ();

A- -; A.display (); }

Результат:

N = 9 X = 19

N = 10 X = 20

N = 9 X = 19

N = 10 X = 20

N = 9 X = 19

Перегрузка операции присваивания

Перегрузку операции ”=” разрешается реализовывать только через компонентную функцию класса!

Рассмотрим перегрузку для класса комплексных чисел:

Complex& Complex:: operator = (Complex & z)

{ re = z.re; im = z. im;

return * this; }

При выполнении

c2=c1;

операция функция вызывается для объекта с2, объект с1 передается в нее как параметр. Данным объекта с2 присваиваются данные объекта с1.

Функция возвращает текущий объект для того, чтобы можно было использовать операцию множественного присваивания:

с3 = с2 = с1;

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

Однако в некоторых случаях, при наличии в классе данных, являющихся указателями на динамические участки памяти, буквальное копирование может привести к утечкам памяти.

 
 


При прямом копировании объект2=объект1 указателю объекта2 присвоится значение указателя объекта1. Участок памяти с данными 2 станет недоступным программе происходит утечка памяти. Уничтожение объекта 1 автоматически уничтожит объект2.

В этом случае необходимо перегрузить операцию присваивания:

class A { int* data;

A (int a)

{ data = new int;

*data= a; }

A (A&z)

{ data = new int;

data=*(z.data);}

A& operator= (const A & z)

{delete data; или { *data = *(z.data);

data = new int; return *this;}

*data = *(z.data);

return * this}

};

Различие между копированием и присваиванием:

Дублирование объекта может быть выполнено и с помощью операции присваивания и с помощью вызова конструктора копирования.

class A { int x;

public:

A (int ax=0){ x=ax; }

int GetX () { return x; }

… };

void main ()

{ A m1(5), m2;

m2 = m1; // операция присваивания

A m3 = m1; // дублирование вызовом конструктора копирования

cout<< m1.GetX () << m2.GetX () << m3.GetX ();

}

В предложении:

m2 = m1;

передача значений выполняется в уже созданный объект. Дублирование объекта производится операцией присваивания по умолчанию.

В предложении:

A m3 = m1;

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

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

Блокировка копирования и присваивания:

Для того, чтобы исключить непреднамеренное дублирование объекта класса, надо в его закрытой части объявить конструктор копирования и перегрузку операции присваивания.

private:

A (A&);

A operator = (A &);

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

Преобразование типов в классах пользователя

Иногда в выражениях целесообразно использовать переменные класса (объекты) с переменными других типов, для этого необходимо определить правила преобразования.

Это можно сделать с помощью перегруженного конструктора класса или с помощью операции – функции преобразования типов.

Рассмотрим опять класс Complex.

Недостаток описания состоит в том, что нельзя выполнять комплексные операции комплексного числа с арифметическими данными:

Complex c1(5.5, 6.5);

Complex c2= c1+ 2;

Complex c2= c1+ ‘0’;

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

Надо объявить конструктор такого вида:

Complex (float r =0, float i =0)

{ re = r; im = i; },

который позволит, например, создавать объекты:

Complex c1(1.5, 2.5);

Complex c1(4.5);

Complex c1;

Рассмотрим операторы описанные выше:

1) 2 преобразуется к 2.0,затем создается временный объект, вызовом конструктора с умалчиваемыми значениями, с данными (2.0, 0.0).

В результате создается объект с2 с данными (7.5, 6.5).

2) ‘0’ преобразуется в целое 48, которое преобразуется в вещественное

48.0, создается временный объект с данными (48.0, 0.0).

В результате создается объект с данными (53.5, 6.5).

Иногда бывает необходимость преобразовать переменные некоторого класса в базовые типы.

Проблема решается с помощью специального оператора преобразования типа.

Рассмотрим это преобразование для класса stroka. Преобразование типа stroka в тип char*.

Чтобы объекты класса можно было бы передавать функциям модуля string.h, надо в описание класса включить компонентную функцию:

1)

operator char* () { return ch; } (1)

И тогда в предложении

stroka s1(“string”)

char* s = s1;

произойдет преобразование объекта s1 к типу char*, правило (1),и переменной s присвоится значение “string”.

2)

Аналогично можно определить в классе преобразование:

operator int () { return len; } (2)

И тогда в предложении:

int l = s1;

переменная класса (объект s1) преобразуется к целому значению по правилу описанному в операторе преобразования (2).

Вопросы:

8) В чем суть объектно-ориентированного подхода к программированию? Дать определение класса.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



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