Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
39
Добавлен:
16.04.2013
Размер:
62.98 Кб
Скачать

Разбор программы rational

• rational(double r) : q(BIG), a(r * BIG){}

Этот конструктор преобразует double в rational.

• operator double(){return static_cast<double>(a)/q;}

А эта функция-член преобразует rational в double.

• inline int greater(int i, int j)

{ return (i >j ? i : j);}

inline double greater(double x , double y)

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

inline rational greater(rational w, rational z)

{ return ( w > z ? w : z); }

Три различные функции перегружены. Наиболее интересная из них имеет перемен­ные типа rational в списке аргументов и такой же возвращаемый тип. Преобразу­ющая функция-член operator double необходима для выполнения сравнения w > z. Позже мы покажем, как перегрузить operator>(), чтобы он мог напрямую принимать типы rational.

• cout << “\ngreater(“ << i << “, “ << j << “) = “

<< greater(i, j)

cout << "\ngreater(“ << x << “, “ << у << “) = "

<< greater(x, y) ;

Первая инструкция выбирает первое определение greater, следуя правилу точного соответствия. Вторая инструкция выбирает второе определение greater, потому что используется стандартное расширяющее преобразование float в double. Тип значения переменной х расширяется до double.

• cout << “) = “ << greater(static_cast<rational>(i), z) ;

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

• zmax = greater(w, z);

Это точное соответствие для третьего определения.

См. упражнение 3 на стр. 220, которое относится к программе rational.

Дружественные функции

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

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

Дружественная функция должна быть объявлена внутри объявления класса, по отношению к которому она является дружественной (с которым она дружит). Функция предваряется ключевым словом friend и может встречаться в любой час класса; это не влияет на ее смысл. Мы предпочитаем размещать объявление friend в открытой части класса. Функция-член одного класса может быть дружественной другому классу. В этом случае для указания ее имени в дружественном классе используется оператор разрешения области видимости. То, что все функции-члены одного класса являются дружественными функциями другого класса, может быть указано как friend class имя_класса.

Следующие объявления иллюстрируют синтаксис

class tweedledee {

. . . . .

friend void alice(); //дружественная функция

int cheshire(); //функция-член

. . . . .

};

class tweedledum {

. . . . .

friend int tweedledee::cheshire();

. . . . .

};

class tweedledumber {

. . . . .

friend class tweedledee; //все функции-члены

. . . . . //из tweedledee получают доступ

};

Рассмотрим класс matrix (см. раздел 6.8, «Двумерные массивы», на стр. 173) и класс vect (см. раздел 6.5, «Класс vect», на стр. 165). Функция, умножающая вектор на матрицу, как представлено в этих двух классах, могла бы быть более эффективной, если бы имела доступ к закрытым членам обоих классов. Это могла бы быть дружественная для обоих классов функция. Как обсуждалось в разделе 6.5, «Класс vect», на стр. 165, безопасный доступ к элементам vect и matrix обеспечивался функцией членом element (). Используя ее, можно написать функцию умножения, не нуждающуюся в статусе дружественной. Однако затраты в виде накладных расходов на вызов функции и проверку границ массива сделали бы такое умножение матриц весьма неэффективным.

В файле matrix2.cpp

class matrix; //предварительное объявление

class vect {

public:

friend vect mру ( const vect& v, const matrix& m);

. . . . .

private:

int* p;

int size;

};

class matrix {

public:

friend vect mpy(const vect& v, const matrix& m) ;

. . . . .

private:

int** p;

int s1, s2;

};

vect mpy(const vect& v, const matrix& m)

{

assert(v.size = = m.sl); //проверка размеров

//использует привелегированный доступ к р в обоих классах

vect ans(m.s2) ;

int i , j ;

for (i = 0; i <= m.ub2(); ++i) {

ans . p [ i ] = 0 ;

for (j = 0; j <= m.ub1(); ++j)

ans.p[i] += v.p[j] * m.p[j][i];

}

return ans;

}

Небольшой нюанс: необходимо предварительное объявление класса matrix, по­скольку функция mру () должна присутствовать в обоих классах и она использует каждый из классов как тип аргумента.

Парадигма ООП состоит в том, что доступ к объектам (в C++ ими являются пе­ременные класса) должен осуществляться через открытые члены. Только функ­ции-члены класса должны иметь доступ к скрытой реализации АТД. Это четкий и строгий принцип разработки. Дружественные функции создают некую двойствен­ность. Они имеют доступ к закрытым членам, не являясь при этом функциями-чле­нами. Их можно использовать для быстрых исправлений в коде, которому необхо­дим доступ к реализации деталей класса. Но такой механизм легко неправильно использовать.

Соседние файлы в папке Тельминов (мб)