常量和非常量函数的重载是如何工作的?

20

STL 充满了像这样的定义:

iterator begin ();
const_iterator begin () const;

由于返回值不参与重载决议,这里唯一的区别在于函数是const。这是否是重载机制的一部分?编译器解决类似以下代码行的算法是什么:

vector<int>::const_iterator it = myvector.begin();
6个回答

13

在你提供的例子中:

vector<int>::const_iterator it = myvector.begin();

如果 myvector 不是 const 的,那么将调用非 const 版本的 begin(),并且会依赖于从迭代器到 const_iterator 的隐式转换。


12
编译器的“算法”如下: 类X的每个成员函数都有一个隐式参数类型为X&(我知道,大多数人认为它是X*,但标准规定,为了重载决议,我们假定它是一个引用)。对于const函数,参数的类型为const X&。因此,如果调用成员函数的两个版本,即const和非const,都是可行的候选项,并且与其他重载决议情况一样选择最佳匹配项。没有任何魔法 :)

谢谢,这很有用。然而,我的问题在于(错误地)假设常量变量是由于它所分配的变量类型而被调用的。@awoodland 解释了这一点。 - davka
为什么只在重载解析时使用引用而不是指针,有没有非显而易见的原因? - Talespin_Kit

4

是的,const修饰符会影响重载。如果此时myvectorconst,那么将调用const版本:

void stuff( const vector<int>& myvector )
{
    vector<int>::const_iterator it = myvector.begin(); //const version will be called
}

vector<int> myvector;    
vector<int>::const_iterator it = myvector.begin(); //non-const version will be called

3

根据C++标准(§13.3.1候选函数和参数列表):

对于非静态成员函数,隐式对象参数的类型为“引用cv X”,其中X是函数所属的类,cv是成员函数声明中的cv限定符。[例如:对于类X的const成员函数,假定额外的参数具有类型“对const X的引用”。]

因此,在您的情况下,如果myvector对象是const,编译器将选择具有隐式对象参数类型为reference to const vectorbegin版本,这是begin的const版本。


3

值得一提的是,C++允许常量方法/函数重载(例如,foo() const),但不允许常量参数重载(例如,bar(int a)和bar(const int a))。


如果它们是引用,你可以重载第二个。 - ConventionalProgrammer
如果它们是引用,你可以重载第二个。 - undefined

2
编译器在编译时确定对象变量是否为const,然后选择相应的重载和其返回类型。
class C {
    public:
        int f() { return 1; }
        float f() const { return 1.5; }
};

// Non const.
C c;
assert(c.f() == 1);

// Convert variable const at compile time.
assert(const_cast<const C&>(c).f() == 1.5);

// Same as above but with an explicit reference.
const C& d = c;
assert(d.f() == 1.5);

// Analogous but with a new const object from the start.
const C e;
assert(d.f() == 1.5);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接