const成员函数中this指针是否会使所有成员具备const属性?
我知道在函数声明后加const限定符时,隐式的this指针会变成const类型,因此不能直接修改任何成员变量。但我有个疑问:在const成员函数中,所有成员变量会自动变成const吗?
为了说明这个问题,我写了下面的示例代码:
#include <vector> struct Foo { int a; int b; }; class Demo { public: Demo() = default; void bar(std::vector<Foo>::iterator it) const {} void baz() const { // 我认为这里应该返回iterator,而不是const_iterator bar(vector.begin()); } private: std::vector<Foo> vector; }; int main(void) { Demo d; d.baz(); return 0; }
在baz()方法里,我调用了std::vector::begin(),根据cppreference的文档,这个方法有两个重载:
iterator begin() noexcept; const_iterator begin() const noexcept;
我的理解是:如果vector是const成员,才会调用返回const_iterator的重载;否则应该调用返回可变iterator的重载,当前代码里vector并不是const的,所以应该走前者。
但用g++ --std=c++17 -Wall编译时,出现了如下错误:
main.cpp:17:13: error: no viable conversion from '__wrap_iter<std::__1::vector<Foo, std::__1::allocator<Foo> >::const_pointer>' to '__wrap_iter<std::__1::vector<Foo, std::__1::allocator<Foo> >::pointer>' bar(vector.begin()); ^~~~~~~~~~~~~~
这说明vector.begin()实际返回了const_iterator而不是iterator。我并没有把vector声明为const,为什么会调用返回const_iterator的重载?是不是因为baz()被声明为const?我知道const成员函数里当前对象的内存不能修改,但没想到这会影响函数重载的选择。
解答
没错,问题的根源就是baz()是const成员函数。
在const成员函数中,隐式的this指针类型是const Demo*,也就是说,通过this访问的所有成员变量都会被视为const类型——哪怕成员变量本身在类里的声明是非const的。
回到你的代码:在baz()里,vector其实是this->vector,而this是const Demo*,所以this->vector的类型就是const std::vector<Foo>。当你调用vector.begin()时,实际上是在一个const的vector对象上调用begin(),自然会匹配到const_iterator begin() const noexcept这个重载,返回const_iterator。
而你的bar()函数接受的是std::vector<Foo>::iterator,const_iterator不能隐式转换成iterator(这是为了防止通过非const迭代器修改const对象的内容),所以编译器报错。
如果要解决这个问题,有两种常见思路:
- 把
bar()的参数改成std::vector<Foo>::const_iterator,因为在const成员函数里本来就不应该修改vector的内容; - 如果确实需要在const成员函数里修改vector(这种场景很少见,因为违背了const成员函数的语义),可以把vector声明为
mutable std::vector<Foo>,这样即使在const成员函数里,它也会被视为非const对象,调用返回普通iterator的重载。不过这种做法要谨慎,只有当成员变量的修改不影响对象的“逻辑const性”时才适合使用。
内容的提问来源于stack exchange,提问作者torez233

