Тогда и статическая функция-член 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) в нем остается, так как является статической. Поскольку это единственная устоявшая функция, она и оказывается наилучшей.
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; // использован операторный синтаксис
}
Если вместо этого использовать синтаксис вызова функции: