title: 操作符"->"
date: 2024-01-16 00:00:00
categories:
- C++
- 箭头
tags: 箭头操作以及偏移量计算 #嘎嘎
操作符"->"
->是一个成员访问的操作,它的作用是通过一个指针来访问它所指向的对象的成员变量或成员函数。它的左边必须是一个指针,右边必须是一个成员的名字。它的含义是,先解引用左边的指针,得到它所指向的对象,然后访问这个对象的右边的成员。也没什么。
".“和”->"的区别
创建个类先
class Entity
{
public:
int x;
public:
void Print() const
{
std::cout << "Hello! " << std::endl;
}
};
对象要调用Print方法就是e.Print(); 或ptr->Print(); 这两个对象一个是Entity,一个是Entity* 。
int main(){
Entity e;
e.Print();
Entity* ptr=new Entity();
ptr->Print();//相当于(*ptr).Print();
ptr->x = 2;//这样访问成员变量
}
在C++中,.
和 ->
都是用来访问结构体或类的成员的运算符,但它们的使用场景不同。
.
运算符用于访问一个实际对象的成员。例如,如果你有一个Vector3
类型的对象vec
,你可以使用vec.x
来访问它的x
成员。->
运算符用于通过指针访问对象的成员。如果你有一个指向Vector3
对象的指针ptr
,你可以使用ptr->x
来访问它指向的对象的x
成员。
简单来说,当你有一个对象时,你使用 .
来访问它的成员;当你有一个指向对象的指针时,你使用 ->
来访问它指向的对象的成员。这是因为指针需要被解引用(dereferenced)来访问指向的对象,而 ->
运算符自动为你做了这个操作。
也可以这么操作:
Entity& entity = *ptr;
entity.Print();
我是看图里这么理解,Entity e;e就是这个内存空间的整体想要访问哪个成员就直接用"."调出来,但如果是Entity* ptr,ptr是个指针,所以要访问成员就需要指向它,所以用->
重载"->"
什么时候需要重载箭头呢,看例子,在之前实现智能指针的时候有个例子:
class ScopedPtr
{
private:
Entity* m_Obj;
public:
ScopedPtr(Entity* entity)
:m_Obj(entity){}
~ScopedPtr()
{
delete m_Obj;
}
Entity* GetObj()
{
return m_Obj;
}
};
简单的实现了智能指针,能自动delete,并且可以通过GetObj()得到私有成员变量.如果我们使用这个ScopedPtr,const ScopedPtr entity = new Entity();
就会发现想要调用Entity的Print方法就得通过
entity.GetObj()->Print(); entity.GetObj()->Print();//entity.GetObj()得到了Entity*类型的m_Obj,就可以通过->来访问Print
这未免长了点,而且不够简洁干净,所以我们就可以在ScopedPtr中重载这个运算符
const Entity* operator->()const
{
return m_Obj;
}
这个重载操作符是为了实现指针类的功能,让它可以像指针一样使用 ->
运算符来访问指向的对象的成员。定义为 Entity*
是为了返回一个 Entity
类型的指针,这样就可以使用 ->
运算符来链式访问 Entity
的成员
现在我们就可以写成entity->Print();来打印Hello
重载详见:
Operator(操作符)| HahのBlog (rhahr.top)
计算变量偏移量
这是一种编程技巧,请看代码:
struct Vector3
{
float x, y, z;
};
int main()
{
int offset=(int)&((Vector3*)nullptr)->y;
std::cout << offset << std::endl;
std::cin.get();
}
这行代码(int)&((Vector3*)nullptr)->y;中
- nullptr表示一个空指针,强转只转换类型而不改变值,(Vector3*)nullptr 将 nullptr 转换为 Vector3 类型的指针,表示一个空的 Vector3 对象的地址
- 然后类型转换成Vector3类型的空指针,然后用->访问y,这里的指针实际上是空的,->y 尝试访问这个空对象的 y 成员,但实际上不会访问任何内存地址,而是返回 y 成员相对于结构体起始位置的偏移量。
- (int)&将这个偏移量的地址转换为整数类型,得到 y 成员的偏移量。
float是4字节大小,所以x,y,z 偏移量为0,4,8 如果结构体中定义时交换y与z,也就是float x,z,y;那么y的偏移量就是8
困惑点:
- nullptr是个空指针,空指针是一个特殊的指针值,通常用
nullptr
(在C++11及以后的版本中)或NULL
(在旧的C++标准中)来表示。空指针没有指向任何有效的内存地址,它的目的是表示一个明确的“无指向”的状态。在代码中,空指针通常用于初始化指针变量,或者在某些操作后将指针设置为一个安全的值,以避免未定义行为。 - 这不同于野指针,野指针是指向未知内存地址或已经释放的内存的指针。野指针的危险在于,它可能指向任意的内存位置,这可能导致程序崩溃或数据损坏。野指针通常是由于指针变量没有被正确初始化,或者在释放了动态分配的内存后没有将指针设置为
nullptr
而产生的。
这里还涉及内存对齐和字节填充,见文章
内存对齐与填充字节| HahのBlog (rhahr.top)