一、先记结论
.:用于对象本体或对象引用访问成员->:用于指针访问成员p->x等价于(*p).x
只要看变量类型就能快速判断:
- 类型是
T或T&,用. - 类型是
T*,用->
二、本质区别
1. 点号 .
a.b 表示“变量 a 本身就是对象(或引用),直接访问成员 b”。
struct Node {
int val;
};
Node n;
n.val = 10;
Node& ref = n;
ref.val = 20;
2. 箭头 ->
p->b 表示“p 是指针,先找到它指向的对象,再访问成员 b”。
Node n;
Node* p = &n;
p->val = 30;
这句完全等价于:
(*p).val = 30;
注意 (*p).val 里的括号不能省,因为 . 的优先级高于 *。
三、为什么容易混淆
日常写题时会同时出现“对象”和“对象指针”,特别是链表、二叉树、图等数据结构题。
例如:
Node node;是对象,写node.valNode* node;是指针,写node->val
名称都叫 node,但类型不同,访问符号就不同。
四、class 和 struct 有关系吗
在 . 和 -> 这件事上,class 与 struct 没有区别。
二者都支持这两种访问方式,是否能用只由“你手里是对象还是指针”决定。
常见差异只是默认权限:
class默认privatestruct默认public
五、典型使用场景
1. 用 . 的场景
- 栈上对象
- 作为成员的对象
- 引用变量
Student s;
s.name = "Tom";
Student& rs = s;
rs.name = "Jerry";
2. 用 -> 的场景
- 裸指针(
T*) - 动态分配对象
- 链表/树节点指针
- 智能指针(
unique_ptr、shared_ptr)
auto p = std::make_unique<Student>();
p->name = "Alice";
六、常见错误
错误 1:对指针使用 .
Node* p;
p.val = 1; // 错误
错误 2:对对象使用 ->
Node n;
n->val = 1; // 错误
错误 3:忘记空指针检查
if (p != nullptr) {
cout << p->val << '\n';
}
七、示例:2236. 判断根结点是否等于子结点之和
给你一个 二叉树 的根结点 root,该二叉树由恰好 3 个结点组成:根结点、左子结点和右子结点。
题目代码:
class Solution {
public:
bool checkTree(TreeNode* root) {
return root->val == root->left->val + root->right->val;
}
};
这里 root 的类型是 TreeNode*,所以要写:
root->valroot->leftroot->right
如果写 root.val 会报错,因为 root 不是对象本体,而是对象地址。
八、速查表
| 变量类型 | 写法 | 示例 |
|---|---|---|
T |
. |
obj.x |
T& |
. |
ref.x |
T* |
-> |
ptr->x |
| 智能指针 | -> |
sp->x |
九、总结
判断原则只有一条:看类型。
- 对象/引用:用
. - 指针:用
->
把 -> 在脑中翻译成“先解引用再点号”,很多细节会立刻清晰。