C++学习笔记----7、使用类与对象获得高性能(一)---- 书写类(3)
2.4、this指针
每个正常的成员函数调用都会隐含地传递一个指针给到对象,它就是被可能我的天this的隐藏参数。使用该指针访问数据成员或者调用成员函数,也可以将其传递给其他的成员函数或者函数。有时候它对消除有歧义的名字很有用。例如,可以给SpreadsheetCell类定义一个value的数据成员而不是m_value。这种情况下,setValue()可能就会像下面:
void SpreadsheetCell::setValue(double value)
{
value = value; // Confusing!
}
这行代码是不是很令人迷惑。你的value到底是指哪个:是作为参数传递的那个还是对象成员的那个?
有些编译器或者编译器设置,上面令人迷惑的代码行能够正常编译,而不会生成报警或错误,但是不会生成代期待的正确结果。
为了不让这些名字产生歧义,可以使用this指针:
void SpreadsheetCell::setValue(double value)
{
this->value = value;
}
然而,如果你使用了我们以前讨论过的命名规范,你就永远不会碰到这种名字冲突的情况。
也可以使用this指针来调用一个作为参数的对象的成员函数的指向对象的指针。例如,假设你写了一个printCell()的单独的函数(不是成员函数)如下:
void printCell(const SpreadsheetCell& cell)
{
println("{}", cell.getString());
}
如果你想从setValue()成员函数中调用printCell(),一定要传递*this作为参数给到printCell()一个对于SpreadsheetCell的引用,setValue()在其上操作:
void SpreadsheetCell::setValue(double value)
{
this->value = value;
printCell(*this);
}
注意:不要写printCell()函数,写一个我们以前解释过的客户化的格式会比较方便。可以使用下面的代码来打印一个叫做myCell的SpreadsheetCell的对象:
std::println("{}", myCell);
换一种方式,可以重载<<操作符,这个我们以后讨论,可以写成下面这样:
cout << myCell << endl;
3、显式对象参数(c++23标准)
从c++23开始,不用再依赖于编译器提供隐式的this参数,可以使用显式对象参数,通常是一个引用类型。下面的代码段用显式对象参数实现了前面的SpreadsheetCell的setValue()成员函数
void SpreadsheetCell::setValue(this SpreadsheetCell& self, double value)
{
self.m_value = value;
printCell(self);
}
setValue()的第一个参数现在就是显式对象参数,通常叫做self,但是你可以使用任何你想使用的名字。self的类型以this关键字开头。该显式对象参数一定要是成员函数的第一个参数。一旦使用了显式对象参数,该函数就不再有隐式定义的this;因此,在setValue()函数体中,必须显式使用self来访问SpreadsheetCell中的任何东东。
使用显式对象参数调用成员函数与使用隐式this参数并没有什么不同。即使setValue()现在指定了两个参数,self与value,你还是会传递一个单独的参数来调用它,该参数就是你想设置的value:
SpreadsheetCell myCell;
myCell.setValue(6);
如示例使用显式对象参数并没有什么好处,甚至使代码更难读。然而,在下面这些情况下是非常有用的:
- 提供更显式的语法来书写引用验证的成员函数,这个我们以后会讨论。
- 对于成员函数模板,其显式对象参数的类型是一个模板类型的参数。在实现const与non-cost重载成员函数时避免代码重复会非常有用,这个我们以后也会讨论。
- 书写递归lambda表达式时,这个我们以后再讨论。