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