Тогда и статическая функция-член mf(int*), и константная функция mf(int), и неконстантная функция mf(double) включаются в множество кандидатов для показанного ниже вызова. Но какие из них войдут в множество устоявших?

int main() {

const myClass mc;

double dobj;

mc.mf( dobj ); // какая из функций-членов mf()?

}

Исследуя преобразования, которые надо применить к фактическим аргументам, мы обнаруживаем, что устояли функции mf(double) и mf(int). Тип double фактического аргумента dobj точно соответствует типу формального параметра mf(double) и может быть приведен к типу параметра mf(int) с помощью стандартного преобразования.

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

mc – это константный объект, для которого можно вызывать только нестатические константные функции-члены. Следовательно, неконстантная функция-член mf(double) исключается из множества устоявших, и остается в нем единственная функция mf(int), которая и вызывается.

А если константный объект использован для вызова статической функции-члена? Ведь для такой функции нельзя задавать спецификатор const или volatile, так можно ли ее вызывать через константный объект?

class myClass {

public:

static void mf( int );

char mf( char );

};

int main() {

const myClass mc;

int iobj;

mc.mf( iobj ); // можно ли вызывать статическую функцию-член?

}

Статические функции-члены являются общими для всех объектов одного класса. Напрямую они могут обращаться только к статическим членам класса. Так, нестатические члены константного объекта mc недоступны статической mf(int). По этой причине разрешается вызывать статическую функцию-член для константного объекта с помощью операторов "точка" или "стрелка".

Таким образом, статические функции-члены не исключаются из множества устоявших и при наличии спецификаторов const или volatile у объекта, для которого они вызваны. Статические функции-члены рассматриваются как соответствующие любому объекту или указателю на объект своего класса.

В примере выше mc – константный объект, поэтому функция-член mf(char) исключается из множества устоявших. Но функция-член mf(int) в нем остается, так как является статической. Поскольку это единственная устоявшая функция, она и оказывается наилучшей.

<p>15.12. Разрешение перегрузки и операторы A</p>

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

SomeClass sc;

int iobj = sc + 3;

Как компилятор решает, что следует сделать: вызвать перегруженный оператор для класса SomeClass или конвертировать операнд sc во встроенный тип, а затем уже воспользоваться встроенным оператором?

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

* При разрешении перегрузки используется все та же процедура из трех шагов, представленная в разделе 9.2: Отбор функций-кандидатов.

* Отбор устоявших функций.

* Выбор наилучшей из устоявших функции.

Рассмотрим эти шаги более детально.

Разрешение перегрузки функции не применяется, если все операнды имеют встроенные типы. В таком случае гарантированно употребляется встроенный оператор. (Использование операторов с операндами встроенных типов описано в главе 4.) Например:

class SmallInt {

public:

SmallInt( int );

};

SmallInt operator+ ( const SmallInt &, const SmallInt & );

void func() {

int i1, i2;

int i3 = i1 + i2;

}

Поскольку операнды i1 и i2 имеют тип int, а не тип класса, то при сложении используется встроенный оператор +. Перегруженный operator+(const SmallInt &, const SmallInt &) игнорируется, хотя операнды можно привести к типу SmallInt с помощью определенного пользователем преобразования в виде конструктора SmallInt(int). Описанный ниже процесс разрешения перегрузки в таких ситуациях не применяется.

Кроме того, разрешение перегрузки для операторов употребляется только в случае использования операторного синтаксиса:

void func() {

SmallInt si(98);

int iobj = 65;

int res = si + iobj; // использован операторный синтаксис

}

Если вместо этого использовать синтаксис вызова функции:

Перейти на страницу:

Похожие книги