C++ 类与对象详解:从结构体到面向对象编程
C++ 的面向对象编程(OOP)核心是 类(Class) 和 对象(Object)。类是用户自定义的数据类型,用于封装数据(属性)和操作数据的方法(行为);对象则是类的实例。本文将从 C 风格结构体 引入,逐步深入讲解 C++ 的类和对象,结合代码和详细说明。
1. 从 C 风格结构体到 C++ 类
1.1 C 风格结构体(Struct)
在 C 语言中,结构体(struct
)用于将多个相关变量组合成一个复合类型:
#include <iostream>
#include <cstring> // 用于 strcpy// C 风格结构体:表示一个学生
struct StudentC {char name[50]; // 姓名(字符数组)int age; // 年龄float score; // 分数
};int main() {// 创建结构体变量并初始化StudentC s1;strcpy(s1.name, "Alice"); // C 风格字符串赋值s1.age = 20;s1.score = 95.5f;// 访问结构体成员std::cout << "Name: " << s1.name << ", Age: " << s1.age << ", Score: " << s1.score << std::endl;return 0;
}
说明:
数据完全公开,无法控制访问权限
操作数据的行为(函数)与数据本身分离(结构体仅包含数据,操作需额外函数实现)
缺乏数据保护机制,容易导致非法修改
1.2 C++ 结构体(增强版)
C++ 保留了 struct
,但允许在结构体内定义函数(方法),并支持访问控制(public
/private
):
#include <iostream>
#include <string> // 使用 std::string 替代字符数组// C++ 结构体(带方法)
struct StudentCpp {std::string name; // 更安全的字符串int age;float score;// 结构体内定义方法:打印学生信息void printInfo() {std::cout << "Name: " << name << ", Age: " << age << ", Score: " << score << std::endl;}
};int main() {StudentCpp s2;s2.name = "Bob"; // 直接赋值s2.age = 21;s2.score = 88.0f;s2.printInfo(); // 调用结构体方法return 0;
}
说明:
- C++ 的
struct
默认成员是public
的(与class
默认private
不同)。 - 可以在结构体内定义方法,但通常更推荐用
class
表达面向对象概念。
1.3 从结构体到类的关键转变
C++ 中 class
和 struct
的唯一区别是默认访问权限不同:
类是结构体的升级版,通过 访问修饰符 控制成员的可见性,并强制将数据和方法绑定在一起:
// 使用 class 关键字
class Point {int x; // 默认 privateint y; // 默认 privatepublic:void print() {cout << "(" << x << ", " << y << ")" << endl;}void set(int newX, int newY) {if (newX >= 0 && newY >= 0) { // 添加验证逻辑x = newX;y = newY;}}int getX() const { return x; } // const 成员函数int getY() const { return y; }
};int main() {Point p1;p1.set(3, 4);// p1.x = 5; // 错误:x 是 private 成员cout << p1.getX() << endl; // 正确:通过公共接口访问return 0;
}
关键概念:
封装:将数据和行为组合在一起,并控制访问权限
访问修饰符:
public
:公开的,任何代码都可以访问private
:私有的,只有类内部可以访问protected
:受保护的,类内部和派生类可以访问
const 成员函数:承诺不修改对象状态的成员函数
2. 类的核心特性详解
2.1 构造函数与初始化
基本构造函数
- 构造函数:
- 特殊方法,在创建对象时自动调用,用于初始化数据。
- 语法:
ClassName(参数列表) : 初始化列表 {}
。
class Student {string name;int age;double score;public:// 构造函数Student(const string& n, int a, double s) {name = n;age = a;score = s;}void display() const {cout << name << ", " << age << "岁, 成绩: " << score << endl;}
};int main() {Student stu("张三", 18, 90.5); // 调用构造函数stu.display();return 0;
}
初始化列表(更高效的初始化方式)
class Student {string name;int age;double score;public:// 使用初始化列表的构造函数Student(const string& n, int a, double s) : name(n), age(a), score(s) { // 初始化列表// 构造函数体}
};
初始化列表的优势:
对于类类型成员,直接调用拷贝构造函数而非先默认构造再赋值
对于 const 成员和引用成员,必须在初始化列表中初始化
执行效率更高
默认构造函数
class Student {// ... 其他成员同上public:Student() : name("无名"), age(0), score(0) {} // 默认构造函数// 也可以使用默认参数实现Student(const string& n = "无名", int a = 0, double s = 0) : name(n), age(a), score(s) {}
};int main() {Student stu1; // 调用默认构造函数Student stu2("李四"); // 使用默认参数return 0;
}
2.2 静态成员(类共享数据)
静态成员属于类本身,而非单个对象,所有对象共享同一份数据:
#include <iostream>class Student {
private:static int studentCount; // 静态成员:记录学生总数std::string name;public:Student(const std::string& n) : name(n) {studentCount++; // 创建对象时增加计数}static int getStudentCount() { // 静态方法:访问静态成员return studentCount;}
};// 初始化静态成员(必须在类外定义)
int Student::studentCount = 0;int main() {Student s6("Eve");Student s7("Frank");std::cout << "Total Students: " << Student::getStudentCount() << std::endl; // 输出 2return 0;
}
说明:
- 静态成员需在类外单独定义和初始化。
- 静态方法只能访问静态成员,不能访问非静态成员。
3. 对象:类的实例
3.1 对象的创建与销毁
对象是类的实例,通过构造函数初始化,析构函数清理资源:
#include <iostream>class Resource {
public:Resource() {std::cout << "Resource acquired!" << std::endl;}~Resource() { // 析构函数std::cout << "Resource released!" << std::endl;}
};int main() {{Resource res; // 创建对象,调用构造函数// ... 使用 res ...} // 离开作用域,自动调用析构函数return 0;
}
输出:
Resource acquired!
Resource released!
析构函数特点:
名称是
~
加类名,无参数无返回值在对象生命周期结束时自动调用
用于释放资源、清理内存等收尾工作
如果不显式定义,编译器会生成默认析构函数
3.2 对象作为函数参数
对象可以通过值传递、引用传递或指针传递:
#include <iostream>class Point {
public:int x, y;Point(int xVal, int yVal) : x(xVal), y(yVal) {}
};// 1. 值传递(拷贝对象)
void printPointByValue(Point p) {std::cout << "Value: (" << p.x << ", " << p.y << ")" << std::endl;
}// 2. 引用传递(避免拷贝)
void printPointByRef(const Point& p) {std::cout << "Ref: (" << p.x << ", " << p.y << ")" << std::endl;
}int main() {Point p1(10, 20);printPointByValue(p1); // 拷贝 p1printPointByRef(p1); // 直接引用 p1return 0;
}
建议:
- 大型对象使用
const
引用传递(避免拷贝开销)。 - 需要修改对象时使用非
const
引用或指针。
4. 总结
概念 | 说明 |
---|---|
结构体(Struct) | C 风格数据组合,C++ 增强后支持方法,默认成员公开。 |
类(Class) | 封装数据和方法,通过访问修饰符控制可见性,支持构造函数/析构函数。 |
对象 | 类的实例,通过构造函数初始化,析构函数清理资源。 |
静态成员 | 属于类而非对象,所有对象共享同一份数据。 |
封装性 | 通过私有数据和公有方法保护数据安全性。 |