直接上代码
#include <iostream>
#include <string>
class Entity
{
public:
void Print() const { std::cout << "Hello!" << std::endl; }
};
int main()
{
Entity e;
e.Print();
Entity* ptr = &e;
Entity& entity = *ptr;
entity.Print();
(*ptr).Print();
ptr->Print();
}
我们可以思考一下为什么entity.Print(); (*ptr).Print(); ptr->Print();都可以正确的调用hello?
在C++中,指针是一个变量,它存储了另一个变量的内存地址。而引用是已存在变量的别名。它们都可以用来访问和操作变量,但是有一些语法和使用上的区别。
在C++中,Entity& entity = *ptr;
这段代码定义了一个对 Entity
类型的引用 entity
,并将其初始化为指针 ptr
所指向的对象。这里有几个关键点需要理解:
引用(Reference):在C++中,引用是已存在变量的别名。一旦一个引用被初始化为某个对象,它就不能再被改变为引用另一个对象。引用在语法上表现得就像一个变量,但实际上它并不拥有自己所引用的对象的内存空间。
解引用(Dereferencing):*ptr
是一个解引用操作,它返回指针 ptr
所指向的对象。在这个例子中,ptr
指向 e
,所以 *ptr
就是 e
。
Entity& entity:这定义了一个名为 entity
的引用,该引用指向一个 Entity
类型的对象。
初始化:Entity& entity = *ptr;
这行代码将 entity
初始化为 *ptr
,即 e
。这意味着 entity
现在成为了 e
的一个别名。对 entity
的任何操作都将直接作用在 e
上,因为它们是同一个对象的不同名字。
现在,既然 entity
是 e
的一个引用,你可以通过 entity
来访问 e
的任何公有成员,就像直接通过 e
一样;所以我们可以像前面一样直接用“.”来访问类中的公有成员。因此,对 entity
的任何修改都会反映到 e
上,因为它们是同一个对象。同样地,如果 e
被销毁(例如离开了其作用域),那么对 entity
的任何访问都将是未定义的,因为它们都指向了同一个不再存在的对象。
ptr->Print();
这是使用指针调用其指向对象的成员函数的常见方式。->
运算符首先解引用指针(即获取指针指向的对象的地址),然后调用该对象的成员函数。所以,ptr->Print();
实际上是先解引用 ptr
得到 e
,然后调用 e
的 Print
方法。
(*ptr).Print();
这里,我们首先使用 *
运算符来解引用 ptr
,得到 e
的一个副本(但实际上由于 e
是一个对象而不是基本类型,这里得到的是 e
的引用,但我们可以暂时忽略这个细节)。然后,我们使用 .
运算符来调用 e
的 Print
方法。虽然这里看起来我们好像创建了一个 e
的副本,但实际上因为 Entity
是一个类类型,所以 *ptr
实际上返回的是 e
的引用,而不是副本。因此,这和直接调用 e.Print();
是等效的。
总结一下:ptr->Print();
和 (*ptr).Print();
都是有效的,因为它们都在做同样的事情:先解引用指针 ptr
得到 e
,然后调用 e
的 Print
方法。只是语法上稍有不同而已。