在学习 C++ 时,常常会遇到访问对象成员的两种符号:. 和 ->。这两个符号看似简单,但它们的正确使用却需要理解指针和对象的本质差异。对于 C/C++ 小白来说,这篇文章将详细解释它们的区别,帮助你在编程时少踩坑。 
一、. 与 -> 的基本概念 
在 C++ 中,. 和 -> 是用来访问类(或结构体)成员的操作符。它们的使用场景有所不同: 
	- . (点号操作符):用于访问非指针对象的成员。
 
	- -> (箭头操作符):用于访问指针对象所指向的成员。
 
 
这两个操作符的作用是类似的,但它们适用的对象类型不同。 
二、. 的用法 
点号操作符 . 是最简单的成员访问操作符,适用于普通对象。通过对象名和点号,我们可以直接访问该对象的成员函数或成员变量。 
示例代码 
	
		
			| 
			 1 
			2 
			3 
			4 
			5 
			6 
			7 
			8 
			9 
			10 
			11 
			12 
			13 
			 | 
			
			 #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 函数。 
总结 如果你创建的变量是一个普通对象(栈分配或静态分配),就用 . 访问其成员。点号操作符只能用于非指针对象。 
三、-> 的用法 
箭头操作符 -> 用于指针对象。它的作用是隐式解引用指针,访问指针所指对象的成员。 
示例代码 
	
		
			| 
			 1 
			2 
			3 
			4 
			5 
			6 
			7 
			8 
			9 
			10 
			11 
			12 
			13 
			14 
			 | 
			
			 #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 的简写。这一点可以通过以下代码理解: 
示例代码 
	
		
			| 
			 1 
			2 
			3 
			4 
			5 
			6 
			7 
			8 
			9 
			10 
			11 
			12 
			13 
			14 
			15 
			16 
			17 
			 | 
			
			 #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) 是完全等价的。 
为什么有 ->? 
如果没有 ->,我们每次都需要先解引用指针再用点号访问成员,写起来会显得冗长。例如: 
	
		
			| 
			 1 
			 | 
			
			 (*pointer).memberFunction(); 
			 | 
		 
	
 
而 -> 直接简化了这一过程,代码更简洁: 
	
		
			| 
			 1 
			 | 
			
			 pointer->memberFunction(); 
			 | 
		 
	
 
五、如何判断用哪个操作符? 
检查变量类型: 
	- 如果是普通对象,使用 .。
 
	- 如果是指针对象,使用 ->。
 
 
错误提示: 
如果你试图对指针对象使用 .,或者对普通对象使用 ->,编译器会报错: 
	- “type does not have member…”(类型错误)。
 
	- 或者“invalid use of member…” 示例代码
 
 
以下是常见错误示例: 
	
		
			| 
			 1 
			2 
			3 
			4 
			5 
			 | 
			
			 Stack *s = new Stack(); 
			// 错误:指针不能直接用点号访问 
			s.enstack(1); 
			// 正确:使用箭头操作符 
			s->enstack(1); 
			 | 
		 
	
 
六、实战对比示例 
以下是一个综合示例,展示如何在不同情况下使用 . 和 ->: 
示例代码 
	
		
			| 
			 1 
			2 
			3 
			4 
			5 
			6 
			7 
			8 
			9 
			10 
			11 
			12 
			13 
			14 
			15 
			16 
			17 
			18 
			 | 
			
			 #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)来管理指针,减少手动管理内存的风险。
 
 
八、总结 
	- 点号操作符 . 用于普通对象。
 
	- 箭头操作符 -> 用于指针对象,并隐式完成了解引用操作。
 
	- 它们之间有明确的使用场景,并可以通过解引用实现等价转换。
 
 
了解这些基本概念后,可以避免在访问对象成员时犯错。 
    |