C++常量和具有相同名称的可变函数

C++ const and mutable functions with the same name

本文关键字:函数 常量 C++      更新时间:2023-10-16

考虑以下代码。

#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); 

要调用的函数是根据传递对象的cv限定符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的const成员函数,假定额外参数的类型为"reference to const X"。]

因此,如果对象是const,编译器将选择成员函数的版本,该成员函数具有类型为的隐式对象参数,引用常量Object,这是Print()的常量版本。

所有函数重载的工作方式相同。

当考虑重载成员函数时,它包括隐式this参数。如果函数声明为const,则this参数为const Object *。如果函数不是const,则this参数是Object *。由于const限定符会影响函数重载规则,这意味着函数的const性也会影响函数过载规则。

在您的特定示例中,print_obj(obj1)打印const,因为print_obj()被声明为采用const Object&,这意味着它将始终调用Print()const版本。print_obj(obj2)也是如此。

obj1.Print()打印mutable,因为obj1不是const,因此Print()的非const版本是更好的匹配,并且是为函数过载分辨率而选择的。

obj2.Print()打印const,因为obj2const,因此Print()const版本是唯一合适的函数重载。

pobj1->Print()打印mutable,因为*pboj1是非const值,因此选择Print()的非const版本作为函数过载分辨率。

最简单的想法是,如果你只是有会发生什么

void Print(Object &obj);
void Print(const Object &obj);

请记住,对于普通对象,如果有非const版本可用,则选择非const版本;否则选择CCD_ 51版本。以下是分析:

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方法而不是非const方法。

同样适用于挥发性、BTW.