引言
大部分语言支持链式调用,但是在 C++ 中,链式调用有几个坑需要我们注意。本篇文章就是介绍一下 C++ 中链式调用的注意事项。
本次例子中,我们把链式调用分为三类:普通对象的链式调用、对象引用的链式调用、指针的链式调用!
普通对象的链式调用
为了将焦点放到链式调用上,这里所有的代码全部放到
main.cpp
文件中,就不分割文件了。
1 |
|
场景一
1 | int main() |
incr_age_val
方法中,在更新了当前对象的 age
字段之后,返回了 *this
,也就是 person
对象。
我们创建 Person p(10)
对象,然后链式调用之后,获取 age
属性。大家不妨猜一猜此时 age
为多少?
答案:11。
为什么是 11 而不是 16 呢?关键在于 incr_age_val
方法的返回值为 Person
对象,也就是 p 的副本。我们看下图:
incr_age_val
三次调用分别返回了三个不同的 Person
实例。我们输出 age
时,输出的只是 p
实例对应的 age
。所以结果为 11。
如果想得出 age = 16
的结果,只需要获取它的返回值即可:
1 | int main() |
场景二
1 | int main() |
以上代码创建两个对象 p
跟 p1
,然后在获取对象 p
跟 p2
的 age
。猜一猜它们的结果是什么?
答案是:30、80。
我们继续看图,看一看整个调用过程:
每次函数调用之后都会发生值复制,所以第一次调用之后返回的 person 对象值为 30 也就是对象 p 的值。第二次调用 age 此时为 30 然后加上 p1 的 20 结果为 50 生成副本对象参与第三次调用,但是此时的 p 为 30,所以 50 + 30 得到最后的结果 80。
对象引用的链式调用
场景一
1 | int main() |
换成引用之后,结果为我们期待的结果 16 了。因为函数调用之后返回的不再是副本,而是第一个对象的引用。也就是说三次调用递增的都是同一个对象。
场景二
1 | int main() |
猜一猜结果是多少?我们来分析一下:
- 由于返回的是引用,所以
p.incr_age_ref(p1)
之后,p 为 30。 - 再次调用
p.incr_age_ref(p1)
之后,p 为 50。 - 最后调用
incr_age_ref(p)
时,p 为 50,所以两者相加之后为 100。
最终答案:100。
对象指针的链式调用
由于引用的本质就是指针,所以指针的行为跟引用应该一致,不过我们依然测试一下。
场景一
1 | int main() |
我们得到的结果与预期的一直为 16。引用返回的是对象的假名,而指针返回的是对象的地址,所以二者可以等价。结果自然而然一样。
1 | int main() |
由于指针获取的都是当前的最新值,所以跟引用一致,答案为 100!
尾声
链式调用虽然好用,但是我们一定要清楚,函数返回的值是什么以及每次调用中,入参的当前值又是什么?