C++ 类 & 对象(保姆级教程)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
在 C++ 编程的世界中,类 & 对象是面向对象编程(OOP)的核心概念,它们如同构建软件的“积木块”,让开发者能够通过抽象和封装实现高效、可维护的代码设计。无论是构建简单的控制台程序,还是开发复杂的图形界面应用,掌握 C++ 类 & 对象 的原理与实践方法,都是提升编程能力的关键一步。本文将通过循序渐进的讲解、形象的比喻和实用的代码案例,帮助读者理解这一主题。
一、类:蓝图与抽象的结合
1.1 类的定义与作用
类(Class) 是对现实世界或逻辑世界中某一类事物的抽象描述,它定义了一组属性(数据成员)和行为(成员函数)。可以将其想象为一座建筑的“设计蓝图”:蓝图中规定了房间的布局、门窗的位置(属性),以及如何建造(行为),但蓝图本身并不是实际的建筑。
例如,假设我们要描述“学生”的特征:
class Student {
public:
std::string name; // 属性:姓名
int age; // 属性:年龄
void study() { // 行为:学习
std::cout << name << " is studying." << std::endl;
}
};
在这个例子中,Student
类定义了学生的姓名、年龄以及学习行为。
1.2 成员函数与数据成员
- 数据成员(Data Members):存储对象的状态,例如
name
和age
。 - 成员函数(Member Functions):定义对象的行为,例如
study()
方法。
1.3 类与结构体(struct)的区别
在 C++ 中,struct
与 class
的语法相似,但默认访问权限不同:
struct
的成员默认为public
;class
的成员默认为private
。
struct Point {
int x; // public 成员
int y;
};
class Vector {
private:
int x; // private 成员
int y;
};
二、对象:类的实例化
2.1 对象的创建与初始化
对象(Object) 是类的具体实例,如同根据蓝图建造的“实际建筑”。通过 new
或直接定义变量的方式创建对象:
// 直接定义对象
Student alice;
alice.name = "Alice";
alice.age = 20;
alice.study(); // 输出:Alice is studying.
// 动态分配内存(需手动释放)
Student* bob = new Student();
bob->name = "Bob";
bob->age = 21;
delete bob; // 避免内存泄漏
2.2 对象的生命周期
对象的生命周期由其作用域或内存分配方式决定。例如:
- 局部对象在函数结束时自动销毁;
- 动态分配的内存需通过
delete
显式释放。
三、成员函数的深入解析
3.1 普通成员函数与静态成员
- 普通成员函数:与对象实例绑定,可以访问所有成员(包括
private
)。 - 静态成员(Static Members):属于类本身而非对象,通过
class::member
访问:
class Counter {
public:
static int total; // 静态数据成员
Counter() { total++; }
};
int Counter::total = 0; // 静态成员需外部定义
int main() {
Counter a, b;
std::cout << Counter::total; // 输出:2
}
3.2 构造函数与析构函数
- 构造函数(Constructor):无返回类型,与类名相同,用于初始化对象:
class Person {
public:
std::string name;
int age;
Person(std::string n, int a) : name(n), age(a) {} // 初始化列表
};
Person john("John", 30); // 直接调用构造函数
- 析构函数(Destructor):名称前加
~
,在对象销毁时自动调用,用于释放资源:
class FileHandler {
public:
~FileHandler() {
std::cout << "Closing file..." << std::endl;
}
};
FileHandler fh; // 对象销毁时自动调用析构函数
四、访问权限与封装
4.1 访问修饰符
C++ 提供三种访问权限:
| 访问权限 | 说明 |
|----------|------|
| public
| 所有代码均可访问 |
| private
| 仅类内部成员函数可访问 |
| protected
| 类内部和派生类可访问 |
class BankAccount {
private:
double balance; // 私有数据,外部无法直接修改
public:
void deposit(double amount) {
balance += amount;
}
};
4.2 封装(Encapsulation)的重要性
通过将数据设为 private
,并提供 public
方法操作数据(如 deposit()
),可以实现数据的封装,避免外部直接篡改,从而提升代码安全性与可维护性。
五、继承:代码复用的桥梁
5.1 继承的基本语法
继承(Inheritance) 允许新类(子类)继承现有类(基类)的属性和行为,从而实现代码复用。使用 :
关键字指定继承关系:
class Vehicle {
public:
void move() {
std::cout << "Moving..." << std::endl;
}
};
class Car : public Vehicle {
public:
void accelerate() {
std::cout << "Accelerating..." << std::endl;
}
};
Car myCar;
myCar.move(); // 继承自 Vehicle
myCar.accelerate(); // 子类新增方法
5.2 继承的类型
继承类型 | 说明 |
---|---|
public | 基类公有成员对子类为公有 |
protected | 基类公有/保护成员对子类为保护 |
private | 基类公有/保护成员对子类为私有 |
六、多态:行为的动态绑定
6.1 多态(Polymorphism)的实现
多态允许不同类的对象通过同一接口调用不同的实现。通过虚函数(Virtual Functions) 和基类指针/引用实现:
class Shape {
public:
virtual void draw() {
std::cout << "Drawing shape..." << std::endl;
}
};
class Circle : public Shape {
public:
void draw() override {
std::cout << "Drawing circle..." << std::endl;
}
};
void drawShape(Shape& s) {
s.draw();
}
int main() {
Circle c;
drawShape(c); // 输出:Drawing circle...
}
6.2 虚函数与纯虚函数
- 虚函数(Virtual Function):通过
virtual
关键字声明,允许子类重写。 - 纯虚函数(Pure Virtual Function):强制子类实现,格式为
virtual void func() = 0
,定义抽象类:
class AbstractClass {
public:
virtual void pureFunc() = 0; // 纯虚函数
};
七、实际案例:学生管理系统
7.1 需求分析
设计一个学生管理系统,支持:
- 学生信息的增删改查;
- 计算平均分;
- 继承扩展教师类。
7.2 代码实现
#include <vector>
#include <string>
class Person {
protected:
std::string name;
int age;
public:
Person(std::string n, int a) : name(n), age(a) {}
virtual void display() const {
std::cout << "Name: " << name << ", Age: " << age << std::endl;
}
};
class Student : public Person {
private:
std::vector<double> scores;
public:
Student(std::string n, int a) : Person(n, a) {}
void addScore(double s) { scores.push_back(s); }
double average() const {
return std::accumulate(scores.begin(), scores.end(), 0.0) / scores.size();
}
void display() const override {
Person::display();
std::cout << "Average Score: " << average() << std::endl;
}
};
class Teacher : public Person {
public:
Teacher(std::string n, int a) : Person(n, a) {}
void teach() {
std::cout << name << " is teaching." << std::endl;
}
};
int main() {
Student alice("Alice", 20);
alice.addScore(90);
alice.addScore(85);
alice.display();
Teacher bob("Bob", 35);
bob.display();
bob.teach();
}
八、最佳实践与常见陷阱
8.1 常见问题与解决方案
- 对象切片(Object Slicing):通过指针或引用传递对象,避免直接赋值:
void process(Person p) { // 子类对象会被切片为 Person 类型
p.display();
}
// 正确做法:使用指针或引用
void process(Person* p) {
p->display();
}
- 避免过度继承:优先使用组合(Composition)而非继承,例如:
class Car { private: Engine engine; // 组合关系 };
8.2 性能优化建议
- 减少不必要的虚函数调用,因虚函数通过虚表(vtable)间接访问,可能影响性能;
- 对于频繁创建的对象,考虑使用
std::unique_ptr
或std::shared_ptr
管理内存。
结论
C++ 类 & 对象 是构建复杂程序的基石,它们通过抽象、封装、继承和多态等特性,让代码更清晰、可维护。从简单的类定义到复杂的继承体系,开发者需要逐步掌握这些工具,并通过实际项目不断实践。无论是设计游戏中的角色系统,还是构建企业级应用,理解 类 & 对象 的原理与应用,都将为你的编程之路奠定坚实的基础。
希望本文能帮助读者在 C++ 的面向对象编程之路上迈出坚实的一步!如果对某个知识点仍有疑问,欢迎在评论区留言讨论。