【一文读懂】对象引用和对象指针

文章介绍了C++中对象引用和指针的区别,以及如何使用它们访问对象成员。指针需要解引用后才能访问对象,而引用作为对象的别名可以直接使用。->运算符简化了通过指针访问成员的过程。同时,文章提醒在声明多个变量时要注意类型定义,以避免混淆。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

最近在看代码时候,又因为这个问题卡了一下,所以再详细分析下

我遇到了类似这样的函数

bool MyClass(sTunnl& sData, sTunnl* sBase)
{
	// 代码   
}

现在解释下

第一个参数,传进来的这个东西,是个对象引用,起别名叫做sData,所以&sData

第二个参数,传进来的这个东西,是个sTunnl对象的指针,*是解引用,相当于是把传进来的东西放在*sBase里面

使用的话,那就sData.get();

例子

#include <iostream>

class MyClass {
public:
    int x;
    MyClass(int val) : x(val) {}
    void print() { std::cout << "Value: " << x << std::endl; }
};

int main() {
    MyClass obj(10); // 创建一个 MyClass 对象
    MyClass &ref = obj; // 创建一个对象引用
    MyClass *ptr = &obj; // 创建一个对象指针

    obj.print(); // 直接访问对象
    ref.print(); // 通过对象引用访问对象
    ptr->print(); // 通过对象指针访问对象

    return 0;
}

在这个示例中,我们首先创建了一个 MyClass 对象 obj。然后,我们创建了一个指向该对象的对象引用 ref 和一个指向该对象的对象指针 ptr

接下来,我们分别使用三种方式访问该对象:直接访问、通过对象引用访问和通过对象指针访问。你可以看到,无论使用哪种方式,都可以成功访问该对象。

那*ptr->print()对吗,*ptr和ptr的意思是一样的吗

*ptr->print() 是不正确的。ptr->print() 是正确的写法,它等价于 (*ptr).print()

ptr 是一个指向对象的指针,而 *ptr 表示指针所指向的对象。因此,ptr 和 *ptr 的意思是不同的。

当你想通过指针访问对象的成员时,可以使用 -> 运算符。例如,如果你想通过指针 ptr 访问对象的 print 方法,可以这样写:

ptr->print();

这等价于先解引用指针,然后再访问对象的成员:

(*ptr).print();

那*ref.print()可以吗

不,*ref.print() 是不正确的写法。如果想通过对象引用访问对象的成员,应该直接使用 . 运算符。例如,如果你想通过对象引用 ref 访问对象的 print 方法,可以这样写:

ref.print();

由于对象引用本身就是对象的别名,因此无需对其进行解引用。可以直接像访问对象本身一样访问对象引用。

为什么对象指针需要解引用,而对象引用就不需要

对象指针和对象引用的工作方式不同。对象指针存储的是对象的地址,而不是对象本身。因此,当你想通过指针访问对象时,需要先解引用指针,才能获取指针所指向的对象。

例如,假设你有一个指向 MyClass 对象的指针 ptr。如果你想通过指针访问该对象的 x 成员,需要先解引用指针,然后再访问成员:

int a = (*ptr).x;

或者使用 -> 运算符简化代码:

int a = ptr->x;

而对象引用则不同。它本身就是对象的别名,因此无需进行解引用。你可以直接像访问对象本身一样访问对象引用。

例如,假设你有一个 MyClass 对象的引用 ref。如果你想通过引用访问该对象的 x 成员,可以直接这样写:

int a = ref.x;

为什么->运算符可以简化代码

-> 运算符是一种特殊的运算符,用于通过指针访问对象的成员。它可以简化代码,因为它允许你直接通过指针访问对象的成员,而无需先解引用指针。

例如,假设你有一个指向 MyClass 对象的指针 ptr。如果你想通过指针访问该对象的 x 成员,可以这样写:

int a = (*ptr).x;

但是这种写法比较繁琐,不够简洁。为了简化代码,你可以使用 -> 运算符:

int a = ptr->x;

这样,你就可以直接通过指针访问对象的成员,而无需先解引用指针。这样的代码更加简洁易读。

这是我画的表格来理解

没有->运算符的话

ptrMyClassget()
0x83484*ptr(*ptr).get()

有->运算符的话

ptrMyClassget()
0x83484ptr->get()

所以有了运算符相当于写法上省了中间这一步

那运算符到底放在什么位置呢

有的人这样写int *a,有的人写成int* a

之所以出现差异C++是因为 C 之上添加了更强大的类型系统


C 样式

C程序员通常从“价值”的角度思考,所以

int *pValue;

读作“pValue的解引用是一个整数”。

C++风格

而C++程序员在“类型”中思考

int* pValue;

读取“pValue 的类型指向 int 的指针”。


当然,编译器完全没有看到任何区别。

不过注意一个事情,就是定义多个变量时小心混乱

int* foo, bar;  // foo will be int*, bar will be int

解决方案是,永远不要在同一行上声明多个变量

其实我个人是喜欢int *p这种的,因为这样我知道*p是表示一个地址

指向类的成员的指针C++中,可以说明指向类的数据成员成员函数的指针。 指向数据成员的指针格式如下: ::* 指向成员函数的指针格式如下: (::*)() 例如,设有如下一个类A: class A { public: int fun (int b) { return a*c+b; } A(int i) { a=i; } int c; private: int a; }; 定义一个指向类A的数据成员c的指针pc,其格式如下: int A:: *pc = &A::c; 再定义一个指向类A的成员函数fun的指针pfun,其格式如下: int (A:: *pfun)(int) = A::fun; 由于类不是运行时存在的对象。因此,在使用这类指针时,需要首先指定A类的一个对象,然后,通过对象来引用指针所指向的成员。例如,给pc指针所指向的数据成员c赋值8,可以表示如下: A a; a.*pc = 8; 其中,运算符.*是用来对指向类成员的指针来操作该类的对象的。 如果使用指向对象的指针来对指向类成员的指针进行操作时,使用运算符->*。例如: A *p = &a; //a是类A的一个对象,p是指向对象a的指针。 p ->* pc = 8; 让我们再看看指向一般函数的指针的定义格式: *() 关于给指向函数的指针赋值的格式如下: = 关于在程序中,使用指向函数的指针调用函数的格式如下: (*)() 如果是指向类的成员函数的指针还应加上相应的对象名对象成员运算符。 下面给出一个使用指向类成员指针的例子: #include class A { public: A(int i) { a=i; } int fun(int b) { return a*c+b; } int c; private: int a; }; void main() { A x(8); //定义类A的一个对象x int A::*pc; //定义一个指向类数据成员的指针pc pc=&A::c; //给指针pc赋值 x.*pc=3; //用指针方式给类成员c赋值为3 int (A::*pfun)(int); //定义一个指向类成员函数的指针pfun pfun=A::fun; //给指针pfun赋值 A *p=&x; //定义一个对象指针p,并赋初值为x cout<*pfun)(5)<<endl; //用对象指针调用指向类成员函数指针pfun指向的函数 } 以上程序定义了好几个指针,虽然它们都是指针,但是所指向的对象是不同的。p是指向类的对象;pc是指向类的数据成员;pfun是指向类的成员函数。因此它们的值也是不相同的。 对象指针对象引用作函数的参数 1. 对象指针作函数的参数 使用对象指针作为函数参数要经使用对象作函数参数更普遍一些。因为使用对象指针作函数参数有如下两点好处: (1) 实现传址调用。可在被调用函数中改变调用函数的参数对象的值,实现函数之间的信息传递。 (2) 使用对象指针实参仅将对象的地址值传给形参,而不进行副本的拷贝,这样可以提高运行效率,减少时空开销。 当形参是指向对象指针时,调用函数的对应实参应该是某个对象的地址值,一般使用&后加对象名。下面举一例子说明对象指针作函数参