在学习 C++ 时,常常会遇到访问对象成员的两种符号:.
和 ->
。这两个符号看似简单,但它们的正确使用却需要理解指针和对象的本质差异。对于 C/C++ 小白来说,这篇文章将详细解释它们的区别,帮助你在编程时少踩坑。
文章目录
一、.
与 ->
的基本概念
在 C++ 中,.
和 ->
是用来访问类(或结构体)成员的操作符。它们的使用场景有所不同:
.
(点号操作符):用于访问非指针对象的成员。->
(箭头操作符):用于访问指针对象所指向的成员。
这两个操作符的作用是类似的,但它们适用的对象类型不同。
二、.
的用法
点号操作符 .
是最简单的成员访问操作符,适用于普通对象。通过对象名和点号,我们可以直接访问该对象的成员函数或成员变量。
示例代码
#include <iostream>
using namespace std;
class Stack {
public:
void enstack(int value) {
cout << "Value enstacked: " << value << endl;
}
};
int main() {
Stack s; // 创建一个普通对象
s.enstack(1); // 通过 . 访问成员函数
return 0;
}
输出结果
Value enstacked: 1
在这里,s
是一个普通对象,s.enstack(1)
通过点号直接调用对象 s
的 enstack
函数。
总结
- 如果你创建的变量是一个普通对象(栈分配或静态分配),就用
.
访问其成员。 - 点号操作符只能用于非指针对象。
三、->
的用法
箭头操作符 ->
用于指针对象。它的作用是隐式解引用指针,访问指针所指对象的成员。
示例代码
#include <iostream>
using namespace std;
class Stack {
public:
void enstack(int value) {
cout << "Value enstacked: " << value << endl;
}
};
int main() {
Stack *s = new Stack(); // 创建一个指针对象
s->enstack(1); // 通过 -> 访问成员函数
delete s; // 释放动态分配的内存
return 0;
}
输出结果
Value enstacked: 1
在这里,s
是一个指向 Stack
对象的指针,s->enstack(1)
隐式解引用该指针并访问其成员函数 enstack
。
总结
- 如果你使用的是指针对象,用
->
访问其成员。 - 箭头操作符相当于
(*pointer).member
的简写。
四、.
和 ->
的等价关系
->
实际上是 (*pointer).member
的简写。这一点可以通过以下代码理解:
示例代码
#include <iostream>
using namespace std;
class Stack {
public:
void enstack(int value) {
cout << "Value enstacked: " << value << endl;
}
};
int main() {
Stack *s = new Stack();
// 使用 -> 操作符
s->enstack(1);
// 等价于使用解引用和点号
(*s).enstack(1);
delete s; // 释放内存
return 0;
}
输出结果
Value enstacked: 1
Value enstacked: 1
通过这段代码可以看出,s->enstack(1)
和 (*s).enstack(1)
是完全等价的。
为什么有 ->
?
如果没有 ->
,我们每次都需要先解引用指针再用点号访问成员,写起来会显得冗长。例如:
(*pointer).memberFunction();
而 ->
直接简化了这一过程,代码更简洁:
pointer->memberFunction();
五、如何判断用哪个操作符?
-
检查变量类型:
- 如果是普通对象,使用
.
。 - 如果是指针对象,使用
->
。
- 如果是普通对象,使用
-
错误提示:
如果你试图对指针对象使用.
,或者对普通对象使用->
,编译器会报错:- “
type
does not have member…”(类型错误)。 - 或者“invalid use of member…”
- “
示例代码
以下是常见错误示例:
Stack *s = new Stack();
// 错误:指针不能直接用点号访问
s.enstack(1);
// 正确:使用箭头操作符
s->enstack(1);
六、实战对比示例
以下是一个综合示例,展示如何在不同情况下使用 .
和 ->
:
示例代码
#include <iostream>
using namespace std;
class Stack {
public:
void enstack(int value) {
cout << "Value enstacked: " << value << endl;
}
};
int main() {
// 普通对象
Stack obj;
obj.enstack(10);
// 指针对象
Stack *ptr = new Stack();
ptr->enstack(20);
delete ptr; // 释放内存
return 0;
}
输出结果
Value enstacked: 10
Value enstacked: 20
七、注意事项
-
指针初始化:
- 使用
->
前,确保指针已初始化,并指向有效对象,否则会导致未定义行为。
- 使用
-
内存管理:
- 对于动态分配的对象,记得使用
delete
释放内存,否则会造成内存泄漏。
- 对于动态分配的对象,记得使用
-
智能指针:
- 在现代 C++ 中,推荐使用智能指针(如
std::shared_ptr
或std::unique_ptr
)来管理指针,减少手动管理内存的风险。
- 在现代 C++ 中,推荐使用智能指针(如
八、总结
- 点号操作符
.
用于普通对象。 - 箭头操作符
->
用于指针对象,并隐式完成了解引用操作。 - 它们之间有明确的使用场景,并可以通过解引用实现等价转换。
了解这些基本概念后,可以避免在访问对象成员时犯错。