成员函数具有一个附加的隐含形参,即指向该类对象的一个指针。这个隐含形参命名为this,与调用成员函数的对象绑定在一起。成员函数不能定义this形参,而是编译器隐含地定义。成员函数可以显式的使用this,但不是必须这么做。
1.何时使用this
必须显式使用this指针:当需要将一个对象作为整体引用而不是引用对象一个成员时。
myScreen.move(4, 0).set('#');
//等价于
myScreen.move(4, 0);
myScreen.set('#');
2.返回*this
在单个表达式中调用move和set操作时,每个操作必须返回一个引用,该引用指向执行操作的那个对象:
class Screen
{
public:
Screen &move(index r, index c);
Screen &set(char);
Screen &set(index, index, char);
};
这样,每个函数都返回调用自己的那个对象。使用this指针可以访问该对象:
Screen &Screen::set(char c)
{
contents[cursor] = c;
return *this;
}
Screen &Screen::move(index r, index c)
{
index row = r * width;
cursor = row + c;
return *this;
}
3.从const成员返回*this
在普通的非const成员函数中,this的类型是一个指向类类型的const指针。可以改变this所指向的值,但不能改变this所保存的地址。在const成员函数中,this的类型是一个指向const类类型对象的const指针。既不能改变this所指向的对象,也不能改变this所保存的地址。
不能从const成员函数返回指向类对象的普通引用。const成员函数只能返回*this作为一个const引用。
给Screen增加一个const成员函数:display操作。将display作为Screen的const成员,则display内部的this将是一个const Screen*型的const:
myScreen.move(4,0).set('#').display(cout); //OK
myScreen.display().set('*'); //Error
问题在于这个表达式是在由display返回的对象上运行set。该对象是const,因为display将其对象作为const返回。不能在const对象上调用set。
4.基于const的重载
解决以上问题,我们定义两个display操作:一个是const,一个不是const。基于成员函数是否为const,可以重载一个成员函数;同样,基于一个指针形参是否指向const,也可以重载一个函数。
01.class Screen
02.{
03.public:
04. //As before
05.
06. Screen &display(std::ostream &os)
07. {
08. do_display(os);
09. return *this;
10. }
11. const Screen &display(std::ostream &os) const
12. {
13. do_display(os);
14. return *this;
15. }
16.
17.private:
18. void do_display(std::ostream &os) const
19. {
20. os << contents;
21. }
22. //As before
23.};
调用:
01.Screen myScreen(5,3);
02.const Screen blank(5,3);
03.myScreen.set('#').display(cout); //调用非const版本
04.blank.display(cout); //调用const版本
5.可变数据成员
可以通过将它们声明为mutable来实现:类的数据成员(甚至是在const成员函数中)可以修改。
可变数据成员永远都不能为const,甚至当它们是const对象的成员时也如此。因此,const成员函数可以改变mutable成员。
01.class Screen
02.{
03.public:
04. //...
05.
06.private:
07. mutable size_t access_ctr;
08.
09. //使用access_ctr来跟踪Screen成员函数的调用频度
10. void do_display(std::ostream &os) const
11. {
12. ++ access_ctr; //OK
13. os << contents;
14. }
15.};
【建议:用于公共代码的私有实用函数】
使用私有实用函数好处:
1)避免在多个地方编写同样的代码
2)当涉及到的动作变得更复杂时,只在一处而不是两处编写这些动作有更显著的意义。
3)希望在开发时增加调试信息,如果只需要改变一个定义来增加或删除调试代码,这样更容易。
4)这个额外的函数调用不需要涉及任何开销。