yandex rtb 1
ГоловнаЗворотній зв'язок
yande share

Объектно-ориентированное программирование

Лекция 7.

Перегруженные методы. Дружественные функции.

 

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

1. Использовать строгое соответствие (если возможно). Этот вариант является предпочтительным, так как подразумевает, что список аргументов в точности совпадает со списком параметров.

2. Попробовать стандартное повышение типа. Повышение – это, например, преобразование float в double, а также bool, char, short в int.

3. Попробовать стандартное преобразование типа. К ним, например, относится преобразование указателей.

4. Попробовать определяемое пользователем преобразование.

5. Использовать, если возможно, соответствие эллипсису (…)

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

 

#include <iostream.h>

#include <cstring>

class ruMoney {

private:

long allcop;

public:

ruMoney(long rub, int cop);

ruMoney() {allcop=0;}

ruMoney(double money);

long getrub() {return static_cast<long>(allcop*0.01);}

int getcop() {return allcop-100*static_cast<long>(0.01*allcop);}

};

ruMoney::ruMoney(long rub, int cop) {

allcop=100*rub+cop;

}

ruMoney::ruMoney(double money) {

allcop=static_cast<long>(100*money);

}

void main() {

ruMoney a(11,0), c;

cout<<a.getrub()<<" rub "<<a.getcop()<<" cop\n";

c=11.01;

cout<<c.getrub()<<" rub "<<c.getcop()<<" cop\n";

}

 

Вывод этой программы:

 

11 rub 0 cop

11 rub 1 cop

 

Существуют случаи, когда было бы желательно функциям - не членам класса предоставить доступ к скрытым членам класса. Это возможно для так называемых дружественных функций. Для описания дружественной функции она должна быть объявлена внутри класса со спецификатором friend. Функция может быть описана в любой части класса, как закрытой, так и открытой. Это не влияет на ее сущность, так как она не принадлежит классу. Естественно, и доступ к такой функции осуществляется как к обычной функции (без точки).

Одна из причин использования дружественных функций состоит в том, что она нуждается в привилегированном доступе к более чем одному классу. Рассмотрим пример. Пусть в дополнение к уже имеющемуся классу ruMoney определен класс usMoney и требуется написать функцию, которая позволяет сравнивать значения этих классов.

 

#include <iostream.h>

#include <cstring>

class usMoney;

class ruMoney {

private:

long allcop;

public:

friend int compare(ruMoney rus, usMoney amr, double kurs);

ruMoney(long rub, int cop);

ruMoney() {allcop=0;}

ruMoney(double money);

long getrub() {return static_cast<long>(allcop*0.01);}

int getcop() {return allcop-100*static_cast<long>(0.01*allcop);}

};

ruMoney::ruMoney(long rub, int cop) {

allcop=100*rub+cop;

}

ruMoney::ruMoney(double money) {

allcop=static_cast<long>(100*money);

}

class usMoney {

private:

long allcent;

public:

friend int compare(ruMoney rus, usMoney amr, double kurs);

amMoney(long dol, int cent);

amMoney() {allcent=0;}

amMoney(double money);

long getdol() {return static_cast<long>(allcent*0.01);}

int getcent() {return allcent-100*static_cast<long>(0.01*allcent);}

};

usMoney:: usMoney (long dol, int cent) {

allcent=100*dol+cent;

}

usMoney:: usMoney (double money) {

allcent=static_cast<long>(100*money);

}

int compare(ruMoney rus, usMoney amr, double kurs) {

if (rus.allcop<amr.allcent*kurs)

return -1;

else if(rus.allcop*kurs==amr.allcent)

return 0;

else

return 1;

}

 

void main() {

ruMoney a(32,95);

double kurs=29.73;

usMoney b=1.11;

cout<<a.getrub()<<" rub "<<a.getcop()<<" cop\n";

cout<<b.getdol()<<" dol "<<b.getcent()<<" cent\n";

cout<<compare(a,b,kurs)<<endl;

}

 

Вывод этой программы

32 rub 95 cop

1 dol 11 cent

-1

 

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

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

Другая причина использования дружественных функций – перегрузка операторов. Язык С++ позволяет перегружать почти все операторы. Это сделано для того, чтобы пользователь класса мог использовать стандартный вид операций, определенный для стандартных типов данных. Логично, например, определить операции +, *, - и т.д. для класса денег.

В программе выше использовался стандартный вид вывода для классов ruMoney и usMoney. Логично было бы переопределить функцию вывода так, чтобы она могла выводить объект нашего класса. Это делается с помощью дружественной функции. Наша программа примет вид:

 

#include <iostream.h>

#include <cstring>

class usMoney;

class ruMoney {

private:

long allcop;

public:

friend int compare(ruMoney rus, usMoney amr, double kurs);

friend ostream& operator<<(ostream& out, ruMoney rus);

ruMoney(long rub, int cop);

ruMoney() {allcop=0;}

ruMoney(double money);

long getrub() {return static_cast<long>(allcop*0.01);}

int getcop() {return allcop-100*static_cast<long>(0.01*allcop);}

};

ruMoney::ruMoney(long rub, int cop) {

allcop=100*rub+cop;

}

ruMoney::ruMoney(double money) {

allcop=static_cast<long>(100*money);

}

ostream& operator<<(ostream& out, ruMoney rus) {

return (out<<rus.getrub()<<" rub "<<rus.getcop()<<" cop");

}

class usMoney {

private:

long allcent;

public:

friend int compare(ruMoney rus, usMoney amr, double kurs);

friend ostream& operator<<(ostream& out, usMoney amr);

usMoney (long dol, int cent);

usMoney () {allcent=0;}

usMoney (double money);

long getdol() {return static_cast<long>(allcent*0.01);}

int getcent() {return allcent-100*static_cast<long>(0.01*allcent);}

};

usMoney:: usMoney (long dol, int cent) {

allcent=100*dol+cent;

}

usMoney:: usMoney (double money) {

allcent=static_cast<long>(100*money);

}

ostream& operator<<(ostream& out, usMoney amr) {

return (out<<amr.getdol()<<" dol "<<amr.getcent()<<" cent");

}

int compare(ruMoney rus, usMoney amr, double kurs) {

if (rus.allcop<amr.allcent*kurs)

return -1;

else if(rus.allcop*kurs==amr.allcent)

return 0;

else

return 1;

}

 

void main() {

ruMoney a(32,95);

double kurs=29.73;

usMoney b=1.11;

cout<<a<<endl<<b<<endl;

cout<<compare(a,b,kurs)<<endl;

}

Вывод ее останется неизменным.

 

9