在 C++ 中使用 this 指针
在本文中,我们将首先了解 this
指针的概念。
然后,我们将借助示例演示其用途。最后,我们将看到 this
与 *this
有何不同。
在 C++ 中使用 this
指针
this
指针只是一个隐式可用指针,在非静态类成员函数范围内,它引用或指向调用对象。如果你没有通过定义得到它,那么让我们看一些基础知识来理解这个概念。
我们知道所有非静态数据成员对每个对象都有一个单独的副本。但是,成员函数代码在所有对象之间共享。
同一类的所有对象在需要调用时都从代码段访问相同的函数定义。编译器需要知道调用对象(当前调用成员函数的对象)信息以访问或更新特定于该特定调用对象的正确数据成员。
那么,在函数定义相同的情况下,编译器如何获取调用对象信息呢?
简单的回答是,在程序的编译过程中,编译器会自动在成员函数中添加一个隐藏的隐式指针参数。这个隐式指针被称为 this
指针。
每当通过特定类对象调用成员函数时,调用对象会自动作为隐藏参数提供给 this
指针。现在,编译器可以使用这个指针来访问或修改特定于调用对象的正确数据成员。
对静态成员的更新或访问并不特定于任何对象。我们甚至可以在不创建类对象的情况下访问这些成员。
因此,编译器不会对这些成员使用 this
运算符。
让我们看一下代码示例,以了解为什么我们说编译器隐式使用 this
指针以及何时使用它很方便。
#include <iostream>
#include <string>
using namespace std;
class Person{
private:
string Name;
public:
Person(string Name) {
this->Name = Name; //this->Name is the private member for this object
}
void PrintName() {
cout<<this->Name<<endl;
}
void PrintName1() {
cout<<Name<<endl;
}
};
int main()
{
Person P("Alexa");
P.PrintName();
P.PrintName1();
return 0;
}
上面的代码示例定义了一个具有两个不同成员函数的 Person
类来打印私有数据成员 Name
。main()
函数中的第一条语句生成一个 Person
对象并将 Alexa
作为参数传递给构造函数。
现在,构造函数中的 this->Name
帮助编译器区分本地参数 Name
和私有数据成员 Name
。
main()
的后续代码通过 P 调用 printName()
和 printName1()
(即 P 成为调用者对象)。
输出:
Alexa
Alexa
两个函数的输出是一样的。这是因为编译器在 PrintName1()
中隐含地在 this->
前面加上 Name
。
C++ 中 this
和*this
的区别
到目前为止,我们已经清楚 this
是指向对象的指针的概念。对于 Person
类型的 obj
,this
是 Person*
类型。
要记住的另一件事是 this
指针始终是一个 rvalue
,不能修改。然而,*this
取消引用 this
指针。
在经历了足够的背景之后,让我们看一个示例代码来了解 this
和*this
之间的区别。
#include <iostream>
using namespace std;
class Counter {
private:
int Count;
public:
Counter() { this->Count = 0; }
void IncreaseCount() { Count++; }
void PrintCount() { cout << this->Count << endl; }
Counter* GetCount_Pointer() { return this; }
Counter GetCount_Copy() { return *this; }
Counter& GetCount_Reference() { return *this; }
};
int main()
{
//Section-A
cout << "Sectio-A" << endl;
Counter C1;
C1.IncreaseCount();
Counter* CounterPtr = C1.GetCount_Pointer(); //CounterObj will be pointing to C1
CounterPtr->IncreaseCount();
C1.PrintCount();
//Section-B
cout << "Section-B" << endl;
Counter C2;
C2 = C1.GetCount_Copy();
C1.IncreaseCount();
C1.PrintCount();
C2.PrintCount();
//Section-C
cout << "Section-B" << endl;
Counter& CounterRef = C1.GetCount_Reference();
CounterRef.PrintCount();
return 0;
}
此代码片段创建了一个 Counter
类,其中包含多个 GetCount
方法的方法。第一个方法(即 GetCount_Pointer
)返回 this
指针的值,它只是调用对象的地址。
GetCount_Copy
方法返回 *this
而返回类型是 Counter
类型的对象。因此,此函数将返回调用对象的深层副本,这意味着修改返回的副本不会影响原始副本。
最后一个 GetCount_Reference
方法也返回 *this
,但此方法的返回类型是一个引用对象(即 Counter&
)。编译器不会创建新的深层副本,而是返回对原始对象的别名或引用。
通过别名所做的任何更改也将反映在原始对象中。
在讨论主驱动代码之前,让我们看一下程序的输出。
输出:
Sectio-A
2
Section-B
3
2
Section-B
3
main
方法的 A 部分首先声明 Counter
类型的 C1
对象并通过 IncreaseCount()
递增其 Count
。稍后,它用 C1.GetCount_Pointer()
返回的地址初始化一个 CounterPtr
指针。
现在,CounterPtr
将指向 C1
。因此,通过 CounterPtr
调用增量函数也会修改 C1
。
B 部分中的 C2 = C1.GetCount_Copy()
将 C1
的所有当前内容深度复制到 C2
,因为 C1.GetCount_Copy()
被 C1
的副本替换。因此,增加 C1
的计数不会影响 C2
。
C 部分声明了一个 Counter
类型的引用变量,并使用 C1.GetCount_Reference()
返回的任何内容对其进行初始化。由于 C1.GetCount_Reference()
返回 C1
的别名,因此 CounterRef
成为 C1
的另一个名称。
语句 Counter& CounterRef = C1.GetCount_Reference();
逻辑上等价于 Counter& CounterRef = C1
。
相关文章
在 C++ 中通过掷骰子生成随机值
发布时间:2023/04/09 浏览次数:169 分类:C++
-
本文解释了如何使用时间因子方法和模拟 C++ 中的掷骰子的任意数方法生成随机数。了解它是如何工作的以及它包含哪些缺点。提供了一个 C++ 程序来演示伪数生成器。
在 C++ 中使用模板的链表
发布时间:2023/04/09 浏览次数:158 分类:C++
-
本文解释了使用模板在 C++ 中创建链表所涉及的各个步骤。工作程序演示了一个链表,该链表使用模板来避免在创建新变量时声明数据类型的需要。
在 C++ 中添加定时延迟
发布时间:2023/04/09 浏览次数:142 分类:C++
-
本教程将为你提供有关在 C++ 程序中添加定时延迟的简要指南。这可以使用 C++ 库为我们提供的一些函数以多种方式完成。
在 C++ 中创建查找表
发布时间:2023/04/09 浏览次数:155 分类:C++
-
本文重点介绍如何创建查找表及其在不同场景中的用途。提供了三个代码示例以使理解更容易,并附有代码片段以详细了解代码。
如何在 C++ 中把字符串转换为小写
发布时间:2023/04/09 浏览次数:63 分类:C++
-
介绍了如何将 C++ std::string 转换为小写的方法。当我们在考虑 C++ 中的字符串转换方法时,首先要问自己的是我的输入字符串有什么样的编码
如何在 C++ 中确定一个字符串是否是数字
发布时间:2023/04/09 浏览次数:163 分类:C++
-
本文介绍了如何检查给定的 C++ 字符串是否是数字。在我们深入研究之前,需要注意的是,以下方法只与单字节字符串和十进制整数兼容。
如何在 c++ 中查找字符串中的子字符串
发布时间:2023/04/09 浏览次数:65 分类:C++
-
本文介绍了在 C++ 中检查一个字符串是否包含子字符串的多种方法。使用 find 方法在 C++ 中查找字符串中的子字符串
如何在 C++ 中把字符串转换为 Char 数组
发布时间:2023/04/09 浏览次数:107 分类:C++
-
本文介绍了在 C++ 中把字符串转换为 char 数组的多种方法。使用 std::basic_string::c_str 方法将字符串转换为 char 数组