Выбрать главу

А если константный объект использован для вызова статической функции-члена? Ведь для такой функции нельзя задавать спецификатор 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) в нем остается, так как является статической. Поскольку это единственная устоявшая функция, она и оказывается наилучшей.

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

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

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; // использован операторный синтаксис

}

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

int res = operator+( si, iobj ); // синтаксис вызова функции

то применяется процедура разрешения перегрузки для функций в пространстве имен (см. раздел 15.10). Если же использован синтаксис вызова функции-члена:

// синтаксис вызова функции-члена

int res = si.operator+( iobj );

то работает соответствующая процедура для функций-членов (см. раздел 15.11).

15.12.1. Операторные функции-кандидаты

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

SmallInt si(98);

int iobj = 65;

int res = si + iobj;

операторной функцией-кандидатом является operator+. Какие объявления operator+ принимаются во внимание?

* Потенциально в случае применения операторного синтаксиса с операндами, имеющими тип класса, строится пять множеств кандидатов. Первые три – те же, что и при вызове обычных функций с аргументами типа класса: множество операторов, видимых в точке вызова. Объявления функции operator+(), видимые в точке использования оператора, являются кандидатами. Например, operator+(), объявленный в глобальной области видимости, – кандидат в случае применения operator+() внутри main():