Учитывая следующий кусок кода.
#include <iostream>
using namespace std;
class Object
{
public:
Object() {}
void Print() const
{
cout << "const" << endl;
}
void Print()
{
cout << "mutable" << endl;
}
};
void print_obj(const Object& obj)
{
obj.Print();
}
int main()
{
Object obj1;
const Object obj2;
Object*const pobj1 = &obj1;
print_obj(obj1);
print_obj(obj2);
obj1.Print();
obj2.Print();
pobj1->Print();
return 0;
}
Выход
const
const
mutable
const
mutable
Мне интересно, как C ++ решает, какой метод вызывать, когда сталкивается со многими изменяемыми методами с одинаковыми именами?
print_obj(obj1);
print_obj(obj2);
Вызываемая функция оценивается на основе резюме-классификатор(const
/volatile
) пропущенного объекта. Обратите внимание, что CV-классификаторы учитываются при разрешении перегрузки функции.
Если переданный объект const
, функция получения const
Аргумент выбран. Если переданный объект неконстантный, то выбирается функция, получающая неконстантный аргумент.
obj1.Print();
obj2.Print();
pobj1->Print();
Если объект const
тогда только позвони const
функция-член может быть вызвана.
Если объект неконстантный, то неконстантная версия преферрируется над const
версия.
Правила четко определены стандартом.
Ссылка:
Стандарт C ++ 03:
§13.3.1 Функции-кандидаты и списки аргументов:
Для нестатических функций-членов тип неявного параметра объекта — «ссылка на cv».
X
» гдеX
это класс, членом которого является функция, а cv является квалификацией cv в объявлении функции-члена. [Пример: для константной функции-члена классаX
предполагается, что дополнительный параметр имеет тип «ссылка на constX
». ]
Так что если объект const
компилятор выберет версию функции-члена, которая имеет неявный объектный параметр типа ссылка на const Object
которая является постоянной версией Print()
,
Таким же образом работает перегрузка всех функций.
При рассмотрении функции-члена для перегрузки, она включает в себя неявное this
параметр. Если функция объявлена const
тогда this
параметр const Object *
, Если функция не const
тогда this
параметр Object *
, поскольку const
квалификаторы влияют на правила перегрузки функций, это означает, что const
Функциональность также влияет на правила перегрузки функций.
В вашем конкретном примере print_obj(obj1)
печать const
так как print_obj()
объявлен как принимающий const Object&
Это означает, что он всегда будет вызывать const
версия Print()
, То же самое с print_obj(obj2)
,
obj1.Print()
печать mutable
так как obj1
не является const
следовательно, неconst
версия Print()
лучше подходит и выбирается для разрешения перегрузки функции.
obj2.Print()
печать const
так как obj2
является const
, Следовательно const
версия Print()
это единственная перегрузка функции, которая подходит.
pobj1->Print()
печать mutable
так как *pboj1
это неconst
значение, так что неconst
версия Print()
выбран для разрешения перегрузки функции.
Самый простой способ думать об этом, что бы произошло, если бы вы просто
void Print(Object &obj);
void Print(const Object &obj);
Имея в виду, что для нормального объекта, если неconst
версия доступна, то неconst
версия выбрана; иначе const
версия выбрана. Ниже приведен анализ:
print_obj(obj1); // print_obj() receives const argument, so `const` is chosen
print_obj(obj2); // same as above
obj1.Print(); // obj1 is not const, so non-const version is chosen
obj2.Print(); // obj2 is const, so must choose const version
pobj1->Print(); // pobj1 is a const pointer pointing to non-const object, so non-const version is chosen
Было бы предпочтительнее, чтобы метод const был неконстантным, если бы оба метода это делали
То же самое работает для летучих, кстати.