在C++中,面向对象编程的第一步就是理解“类”这种自定义类型。类把数据以及操作这些数据的函数组织在一起,形成比C语言结构体更强的封装能力。它不只是语法上的新东西,更是思考程序结构方式的转变:从“先想有哪些函数”变成“先想这个事物有什么属性和行为”。

一、类与对象的基本关系
类(class)是一种用户自定义的类型,它本身不占用实际运行内存,更像是一张设计图纸。对象(object)则是根据这张图纸制造出来的具体实例,只有对象才会在内存中拥有自己的数据空间。很多初学者写下一个class Stack后就以为系统已经准备好了一个栈,其实此时什么都没分配。
从编译角度看,类定义了成员变量的偏移量和成员函数的代码段位置。当用Stack s;这样的语句创建对象时,编译器才按照类布局为s分配栈内存或堆内存。下面代码展示了类定义和对象创建的最简形式:
#include <iostream>
using namespace std;
class Point {
private:
int x;
int y;
public:
void set(int a, int b) {
x = a;
y = b;
}
void print() {
cout << "x=" << x << ", y=" << y << endl;
}
};
int main() {
Point p1; // 对象p1占用内存
Point p2; // 对象p2占用另一份内存
p1.set(3, 4);
p2.set(10, 20);
p1.print();
p2.print();
return 0;
}
上面例子中,p1和p2是两个独立对象,各自拥有x和y的副本。修改p1不会影响p2,这正是面向对象中“封装状态”的基础。如果只写class Point;而不定义对象,程序里不会存在任何Point类型的数据。
二、访问控制与封装意义
C++类通过public、private、protected三种访问说明符决定外部能否直接接触内部成员。将成员变量设为private,只允许通过public成员函数修改,能避免外部随意破坏数据一致性。这种“该隐藏的隐藏,该开放的开放”就是封装。
对比C语言用struct配全局函数的做法,C++类把数据和函数绑死在类型里,调用时自然写成对象.函数(),逻辑更聚合。例如下面这段用类实现的简单计数器,外部不能直接改count,必须通过add方法:
#include <iostream>
using namespace std;
class Counter {
private:
int count;
public:
Counter() : count(0) {}
void add() {
count++;
}
int get() {
return count;
}
};
int main() {
Counter c;
c.add();
c.add();
cout << c.get() << endl; // 输出2
return 0;
}
如果去掉private,让count变成public,任何代码都能写c.count = -100;,计数器就失去了自身约束能力。因此在初步认识类时,应养成“成员变量私有化,行为公开化”的习惯。
三、构造函数与类的初始化
类对象创建时若需要自动做好初始设置,就要用到构造函数。函数名与类名相同、没有返回类型,在对象定义时自动调用。它解决了C语言结构体常忘记初始化导致脏数据的问题。我们可以在构造函数里给成员变量赋合法初值。
以下示例用一个简化版栈类说明构造函数的实际作用。栈需要记录数组和当前位置,构造时把顶部索引置为0,析构略去以聚焦类本身:
#include <iostream>
using namespace std;
class Stack {
private:
int data[100];
int top;
public:
Stack() {
top = 0; // 构造时初始化
}
void push(int v) {
if (top < 100) {
data[top++] = v;
}
}
int pop() {
if (top > 0) {
return data[--top];
}
return -1;
}
int size() {
return top;
}
};
int main() {
Stack s;
s.push(5);
s.push(8);
cout << s.size() << endl; // 输出2
cout << s.pop() << endl; // 输出8
return 0;
}
这个Stack类把数据和操作封装成一个整体,使用者不必关心top怎么变,只要调用push和pop。比起把int data[100]和int top丢在全局再用一堆函数操作,类明显更清晰,也更容易在别的项目里直接复用。
四、从类看面向对象的初步价值
初步认识C++类,不必立刻追求继承、多态等高级特性。先把“用类描述事物、用对象承载状态、用公有函数提供行为”这套模型练熟,就能写出比面向过程更稳的小型模块。当程序里出现多个相似但独立的数据集合时,类可以避免复制粘贴大量函数。
比如管理多个学生成绩,用class Student生成stu[50]数组,比用平行数组char name[50][20]、int score[50]更安全,因为每个学生的姓名和分数在对象内部天然绑定,不会因下标写错而张冠李戴。这种把现实概念映射为代码实体的能力,正是面向对象入门最关键的一步。