Реализация перегруженной операции 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Реализация перегруженной операции



Неполная перегрузка операции «>»

Class Box

{ public:

Bool operator > (Box aBox) const;

// остальная часть тела класса

};

] Box cigarBox (4.0,3.0,1.0);

Box matchbox (1.1,2.2,0.5);

If (cigarbox>matchbox)

Cout<<”The volume of cigar is bigger than matchbox \n“;

Else

Cout<<”cigarBox is smaller than matchbox \n”;

Указатель this всегда будет указывать на объект слева от перегруженной операции. Это значит, что через этот объект (cigarbox) вызывается перегруженная операция operator>, а второй объект, находящийся справа – предается в качестве аргумента в функцию operator>.

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

Bool Box::operator > (Box &aBox) const;

{return this->Volume()>aBox.Volume();}

]

Box cigarBox (4.0,3.0,1.0);

Box matchbox (1.1,2.2,0.5);

If (cigarbox>matchbox)

Cout<<”The volume of cigar is bigger than matchbox \n“;

Else

Cout<<”cigarBox is smaller than matchbox \n”;

 

Double value=20.0;

If (cigar>Value)

Cout<<”The volume of cigar is bigger than”<<Value<<endl;

Else <<”Trololo”;

 

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

 

Bool Box::operator > (double &Value) const;

{return this->Volume()>Value;}

 

Третий вариант развития событий:

If (value>cigarbox)

Тролооло

Else Тралала

This в данном случае никуда не будет указывать.

Функция-член операции всегда представляет левый аргумент как указатель this. Поскольку, в данном случае левый аргумент имеет тип double, мы не можем это реализовать как функцию-член, поскольку в данном случае есть 2 варианта выбора: либо перегружать эту операцию как обычную глобальную функцию, либо как дружественную функцию. Но так, как нет необходимости к прямому доступу к приватным членам класса, то случай с дружественной функцией не нужен. Остается только создать глобальную функцию для перегруженной операции для третьего случая:

Bool operator > (double &Value, Box &aBox) const;

{return Value > aBox.Volume();}

 

Конечный код полной перегрузки операции >

Class Box

{ public:

Box(double lv=1.0,double hv=1.0,double bv=1.0)

{cout<<”Constructor called \n”;

L=lv; H=hv; W=bv;}

Double Volume(){return L*H*W;}

Bool operator > (Box &aBox) const;

{return this->Volume()>aBox.Volume();}

Bool operator > (double &Value) const;

{return this->Volume()>Value;}

~Box(){cout<<”destructor called\n”;}

Private:

Double L,H,W;

};

 

Bool operator > (double &Value, Box &aBox) const;

{return Value > aBox.Volume();}

 

Int main()

{Box smallB(4.0, 2.0, 1.0);

Box mediumB(10.0,4.0,2.0);

If (mediumB>smallB)

Cout<<”mediumB is bigger than smallB\n”;

Else

If (medium>50.0)

Cout<<”the volume of mediumB > then”<<50;

Else

Cout<<”the volume of mediumB isn’t bigger than 50”<<endl;

If(10.0>smallB) cout<<”the V of small is smaller than 10”<<endl;

Else cout<<”\n the V of smallB is bigger than 10”<<endl;

Return 0;

}

 

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

Левые функции

Lvalue (left value)

Rvalue (right value)

X+Y=Z неверно

Z=X+Y верно

W=2Z верно

Const double PI=acos(-1.0);

Double S=2*PI*pow(r,2);

PI=… неверно в связи с тем, что выше указано то, что PI – константа

Int A[10]={0,1,2,3,4,5,6,7,8,9};

A[2]=A[9];

 

Int Sum(int a,int b)

{Return a+b;}

Int main()

{int s=sum(5,10);

}

 

Вызов функции, возвращающей значение, обычно используется в некотором выражении, как например вот здесь. Однако, в С++ функция может возвращать ссылку. Такая возможность появилась исключительно в силу необходимости перегрузки операции присваивания и индексации. Функции, которые возвращают ссылку, могут стоять и справа и слева от знака присваивания. Рассмотрим некоторые проблемы, возникающие при ее использовании. Следующее определение функции приводит к непредсказуемым результатам при выполнении функции.

 

Int &ff(int k)

{return k;}// неправильная функция, возвращающая ссылку, т.к. она возвращает адрес локальной переменной. Но тем самым при запуске программы мы получим только предупреждение, что мы возвращаем адрес локальной переменной, но позволяет запустить программу.

Int f(int &i)

{return I;}// здесь получается правильное значение 5

Int main()

{

Int n=5;

Cout<<f(ff(n))<<endl;

Int m=2

Cout<<f(g)<<endl;

Return 0;

}

 

Как решить эту проблему? Существует 2 способа решения данной проблемы:

1) Передавать параметры по ссылке Int &ff(int &k)

2) Возвращать ссылку на статическую переменную:

{static int a; a=k; return a;}

Второй вариант решения данной проблемы очевиден, т.к. статические переменные будут существовать всё время выполнения программы, не смотря на то, что у них локальная область видимости.

 

Здесь были Регинины каракули…

 

Тривиальный пример:

Левая функция для выбора максимума двух чисел.

Здесь тоже они были…

Double& max(double &x, double &y)

{return (x>y)?x:y;}

{double Z=0.0;

Z=max(10.0,15.0);// обычный вызов

Double a=5, b=6, c=7;

Max(a,b)=10.0; // b=10.0

Max(max(a,b),c)=10 //a=10

Max(max(a,b)=10,c)=0 //b=0.0

//левая функция для минимума массива

Int &Mmin (int d[], int n)

{ int im=0

For (int i=0;i<n;i++)

Im=d[im]<d[i]?im:i;

Return d[im];}

Int main ()

{int x[10]={10,20,40,5,6,7,8,9,50,12}

Int m=Mmin(x,10);

Cout<<”m=”<<m<<endl;

Mmin(x,10)=0; // Минимальный элемент будет заменен на 0

}

 

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

Если мы не представим свою версию операции присваивания, то компилятор использует свою версию, сгенерированную по умолчанию. Версия по умолчанию работает подобно конструктору копирования по умолчанию. А именно выполняет процесс присваивания (копирования) член за членом. Однако, это не одно и то же.

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

Для примера класса Box операция присваивания работает без проблем. Но для других классов, в которых память для членов выделяется динамически, может возникнуть потенциальная угроза породить хаос в программе.

Box box1 (4.0,2.0,3.0);

Box box2=box1;// операция присваивания по умолчанию сработает адекватно

 

Message mess1(“The Visual studio 2010”);

Message mess2=mess1;// могут возникнуть проблемы

 

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

В теле класса Message следует добавить оператор:

Message &operator=(const Message &aMess)

{delete [] pmessage;

Pmessage=new char[strlen(aMess.pmessage)+1];

Strcpy(this->pmessage, aMess.pmessage);

Return *this;}

 

Почему тип возврата функции operator= должна быть ссылка?

Чтобы ответить на этот вопрос, рассмотрим 2 варианта присваивания.

Допустим, что есть 3 объекта типа message.

Mess3=mess2=mess1;

 

… пропуск …

 

Постановка задачи:

Определим сумму двух объектов типа Box как объект Box достаточно большой, чтобы вместить два других, поставленных один на другой. Для этого параметры нового объекта типа Box будут определяться с помощью следующих объектов.

Lbox3=max(Lbox1,Lbox2);

Wbox3=max(Wbox1,Wbox2);

Hbox3=Hbox1+Hbox2;

 

Class Box

{

Public:

Box(double lv=1.0, double wv=1.0, double hv=1.0):

L(lv), W(wv), H(hv)

{L=lv>wv?lv:wv;

W=wv<lv?wv:lv;}

double volume() {return L*W*H;}

Box operator +(const Box& aBox, const Box& Bbox) const;

Return Box(L>aBox.L?L:abox.L, W>aBox.W?W:abox.W,H+=aBox.H);}

Void ShowIt()

{cout<<L<<setw(5)<<W<< setw(5)<<H;}

Private: double L,W,H;};

 

Int main()

{Box smallB(4.0,2.0,1.0);

Box medium (10.0,4.0,2.0);

Box aBox, bBox;

aBox=smallB+medium;

cout<<”the dimentions of abox:\n”;

aBox.Show It();

cout<<endl;

bBox=smallB+medium+aBox;

cout<<”the dimentions of bbox:\n”;

bBox.Show It();

cout<<endl;

return 0;

 

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

 

Class Box

{

Public:

Box(double lv=1.0, double wv=1.0, double hv=1.0):

L(lv), W(wv), H(hv)

{L=lv>wv?lv:wv;

W=wv<lv?wv:lv;}

double volume() {return L*W*H;}

friend Box operator +(const Box& aBox, const Box& Bbox) const;

Void ShowIt()

{cout<<L<<setw(5)<<W<< setw(5)<<H;}

Private: double L,W,H;};

 

Box operator +(const Box& aBox, const Box& Bbox) const;

Return Box(L>aBox.L?L:abox.L, W>aBox.W?W:abox.W,H+=aBox.H);}



Поделиться:


Последнее изменение этой страницы: 2017-02-07; просмотров: 83; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.15.202.214 (0.03 с.)