Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Курс лекций по ОООП.DOC
Скачиваний:
66
Добавлен:
10.05.2014
Размер:
359 Кб
Скачать
☆

3.3. Выбор перегруженной функции

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

Правила сравнения:

  1. Точные совпадения

  2. Расширения

  3. Стандартные преобразования

  4. Преобразования, требующие временные переменные

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

Преобразования, требующие временные переменные: параметр объявлен как ссылка, а аргумент требует преобразования (например, преобразование из float в int&) или задан выражением, значение которого не может быть изменено.

Примеры

void print(int);

void print(const char *);

void print(double);

void print(long);

void print(char);

char c; int i; short s; float f;

print(c); // правило 1; вызывается print(char)

print(i); // правило 1; вызывается print(int)

print(s); // правило 2; вызывается print(int)

print(f); // правило 2; вызывается print(double)

print('a'); // правило 1; вызывается print(char)

print(49); // правило 1; вызывается print(int)

print("a"); // правило 1; вызывается print(const char *)

Пример с ошибками

void f(int, float);

void f(float, int);

Вызов, который приведет к генерации сообщения об ошибке (неоднозначный выбор):

f(1.5, 1.5);

3.5. Друзья класса

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

Функция становится другом после ее объявления в классе с использованием спецификатора friend, например:

Определение

Реализация

а) глобальная функция

class X{

...

friend void f();

public:

void fx();

...

}

void f()

{

...

}

б) функция – член класса

class Y{

...

friend void X::fx();

...

};

void X::fx()

{

...

}

в) класс

class Z{

...

friend class Y;

...

};

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

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

Различия между членами и друзьями класса:

Функция-член

Функция-друг

class Rational{

public:

void print();

...

};

void Rational::print()

{

cout << num;

if(den != 1)

cout << '/' << den;

}

...

Rational x(1,5);

x.print();

class Rational{

public:

friend void print(Rational r);

...

};

void print(Rational r)

{

cout << r.num;

if(r.den != 1)

cout << '/' << r.den;

}

...

Rational x(1,5);

print(x);

Перегруженные операторы – друзья класса:

Бинарный оператор

Унарный оператор (префиксный и постфиксный)

Объявление

friend тип operator знак_оп(op1, op2)

friend тип operator знак_оп(op1)

friend тип operator знак_оп(op1, int)

Реализация

тип operator знак_оп(тип op1, тип op2)

{ ... }

тип operator знак_оп(тип op1)

{ ... }

тип operator знак_оп(тип op1, int)

{ ... }

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

op1 знак_оп op2

эквивалентно: operator знак_оп(op1, op2)

знак_оп op1

op1 знак_оп

Пример перегрузки оператора записи в поток для класса Rational:

class Rational {

friend ostream& operator <<(ostream&, Rational);

...

};

ostream& operator <<(ostream& os, Rational r)

{

os << r.num;

if(r.den == 1)

os << ‘/’ << r.den;

return os;

}