STL向量模板将元素访问器定义为const和非const变体,例如:
reference operator[](size_type __n)
{return *(this->_M_impl._M_start + __n);}
const_reference operator[](size_type __n) const
{return *(this->_M_impl._M_start + __n);}
编译器何时决定使用一个版本而不是另一个版本?向量本身未定义为const,也不存储在其中的元素。所以有两个功能:
A f(int i) const
{ return myVector[i]; }
A f(int i)
{ return myVector[i]; }
我的理解是第一个会调用operator []的const版本并返回一个const A.第二个调用非const版本并返回一个非const A?
对我来说,f()的第一个版本似乎是“正确的”写入,因为函数没有改变任何东西,但调用者返回const A可能会令人惊讶。当然,如果我想要一个const A返回,我应该将f()定义为:
const A f(int i) const //Note the extra const at the start
{ return myVector[i]; }
这会告诉谁在编写调用者以期望const回来。
所以额外的const出现了吗?如果我使用boost :: ptr_vector而不是std :: vector,那么额外的const应用于什么?数据?指针?既?
答案 0 :(得分:7)
这利用了函数重载规则的棘手部分。首先,在方法原型的紧密括号之后的cv限定符就像参数上的cv-qualifiers一样,但它们适用于隐式this
参数。在假设的C ++变体中,你必须声明this
,原型就是这样:
reference operator[](this_type this, size_type n);
const_reference operator[](const this_type this, size_type n);
因此,如果您在上调用方法的对象是const
,则第二个重载是更接近的匹配并将被调用。如果不是,则会调用第一个重载。因此,如果索引const_reference
容器,则会返回const
,如果索引非reference
容器,则会返回const
。然后const_reference
对象强制执行它所指向的容器的只读性质。
有时const_reference
与const reference
相同,有时则不是reference
。对于更复杂的容器,const_reference
是一个具有重要代码的类,并且该代码必须与只读变量不同。该标准始终使用{{1}},以便实现者可以在需要时自由地执行此操作。
答案 1 :(得分:1)
函数声明末尾的const
仅适用于非静态成员函数,意味着*this
是const限定的。
struct A {
void f(int i) const;
void f(int i);
};
void g(const A& x, A& y) {
x.f(); // calls const version
y.f(); // calls non-const version
}
在STL容器中,这种重载用于确定返回的引用或迭代器是否可用于更改容器的元素。您无法通过const
限定容器更改元素。
答案 2 :(得分:1)
在功能中:
A f(int i) const
{ return myVector[i]; }
你正在返回一个非const A.因为你按值返回,所以operator []返回的值(一个const引用)被复制到一个新的A.你正在“丢失”const,但它没有'因为你有一个全新的对象。相反,如果你的班级是这样的:
struct B {
const A& f(int i) const;
A& f(int i);
private:
vector<A> myVector;
};
并使用const B调用f():
const B b;
const A& a = b.f();
你的a将是一个const引用。
答案 3 :(得分:0)
返回const rvalue实际上是没有意义的 - 从const值开始构造一个新值是完全合法的,这就是第一种形式有效的原因。想一想 - 如果你想从某个地方复制,如果你不能在某处写信那就没关系。
如果您返回了引用,那么编译器将不允许您返回A&amp;在const版本中。