24 / 80 · C++11 · 约 8 分钟
this、对象限定与链式接口
this 是隐式对象成员函数所操作对象的指针表达式,其指向类型随成员函数的 const 限定变化。返回 *this 可建立链式接口,但不会延长对象生命周期;静态成员函数没有 this,捕获 this 也不代表拥有对象。
指针表达式而不是隐藏字段
在普通非 const 隐式对象成员函数里,this 的类型是 X*;在 const 成员函数里是 const X*。它是指针类型的纯右值表达式,不能给 this 自身赋值,不能把这种性质误写成“类型一定是 X* const”。成员访问 field 通常可以理解为通过当前对象访问。
this 不是每个对象必须存储的一块指针字段,底层如何传递隐式对象参数属于调用约定。静态成员函数没有当前对象,因此不能使用 this;C++23 的显式对象成员函数也通过声明的对象参数操作对象,而不是使用隐式 this。
const 与引用限定各管一件事
const 成员函数限制通过该对象路径修改普通成员,并不保证全局无副作用,也不自动让成员指针指向的外部对象变成 const。返回当前对象的常用形式是 return *this;,返回类型为 X& 时,后续操作继续作用于同一个对象。
示例给修改操作加上 & 引用限定,只允许对左值调用。这样链式操作不会悄悄从临时对象返回容易悬空的左值引用。需要支持右值时,可以另行设计 && 重载并明确返回值语义,而不是把所有调用者塞进一个引用返回接口。
生命周期比写法更重要
保存 this 或用 lambda 捕获 this,只保存访问路径,不获得所有权。若回调在对象销毁后执行,访问成员就失去合法性。异步接口必须保证对象活到回调完成,或者使用合适的拥有对象、弱引用及失效检查;简单加 const 不能解决悬空。
示例验证 set 返回原对象本身,并通过 const 引用调用只读查询。整个链仍依赖最初的对象存活。即使成员函数体不读取任何字段,也不能通过空指针调用普通成员函数来冒充静态函数;需要无对象的操作就明确声明 static。
容易答错的地方
- 返回 *this 的引用不延长临时对象生命周期;把链式结果长期保存为引用前先确认原对象的存活范围。
- const 限定的是经当前对象访问的权限,不是线程安全保证,也不是深层不可变保证。
运行一个例子
最低标准 C++11 · 完整程序 · 下载 .cpp
#include <cassert>
#include <type_traits>
class Counter {
int value_ = 0;
public:
Counter& set(int value) & {
static_assert(std::is_same<decltype(this), Counter*>::value, "mutable this");
value_ = value;
return *this;
}
int value() const {
static_assert(std::is_same<decltype(this), const Counter*>::value, "const this");
return value_;
}
bool same_object(const Counter& other) const { return this == &other; }
};
int main() {
Counter counter;
Counter& result = counter.set(2).set(5);
const Counter& view = counter;
assert(&result == &counter);
assert(view.value() == 5);
assert(view.same_object(result));
}
在本地编译
g++ -std=c++11 -Wall -Wextra -Wpedantic -pthread objects-this.cpp -o example && ./example预期结果
预期:正常退出、无输出;所有 assert 通过。
CHECK YOUR UNDERSTANDING
合上答案,试着解释。
若把 set 的返回类型改成 Counter,counter.set(2).set(5) 为什么不能继续按原样工作?
查看参考答案
第一次调用返回新的 Counter 值,而不是原对象引用;第二次调用的接收者是临时值,不满足 set 的 & 引用限定,因此编译失败。即使去掉引用限定,第二次修改的也只是副本,原 counter 仍为二。链式接口必须同时考虑返回类型、值类别和对象身份。
继续查证
标准草案链接会随工作草案更新;本文版本标记对应示例最低要求,不表示草案中的所有新规则都适用于旧标准。