C++: 类与对象基础
最后更新:2026-08-26
前面的课程里,我们用结构体把不同类型的变量组合成一个整体。
但真实世界的事物不仅有属性(如姓名、年龄),还有行为(如走路、说话)。
类就是用来描述"事物"的——它把属性和行为封装在一起。
1. 什么是类?
(1) 1.1 生活中的类
| 生活场景 | 程序中的对应 |
|---|---|
| 一份建筑设计图纸(描述了房子的结构) | 类(描述事物的模板) |
| 根据图纸盖好的房子(实际的物体) | 对象(类的实例) |
类 vs 对象:
- 类是模板(描述"学生"应该有哪些属性、哪些行为)
- 对象是实例(根据模板创建的具体事物——"张三"这个学生)
(2) 1.2 为什么需要类?
不用类(用结构体,有限制):
#include <iostream>
#include <string>
struct Student {
std::string name;
int age;
double score;
};
int main() {
Student s1 = {"Alice", 20, 92.5};
// ❌ 结构体不能包含"行为"(如"自我介绍")
return 0;
}
用类(完整):
#include <iostream>
#include <string>
class Student {
public:
std::string name;
int age;
double score;
void introduce() {
std::cout << "我叫 " << name << ",今年 " << age << " 岁。" << std::endl;
}
};
int main() {
Student s1;
s1.name = "Alice";
s1.age = 20;
s1.introduce(); // ✅ 类可以包含"行为"
return 0;
}
2. 类的定义*
(1) 2.1 基本语法
class ClassName {
public:
// members (attributes and behaviors)
};
💡 重点: 类定义以分号结尾!(和结构体一样)
▶ 示例 1:定义 Student 类(难度⭐)
#include <iostream>
#include <string>
class Student {
public:
// attributes (member variables)
std::string name;
int age;
double score;
// behaviors (member functions)
void introduce() {
std::cout << "我叫 " << name << ",今年 " << age << " 岁。" << std::endl;
}
void study() {
std::cout << name << " 正在学习..." << std::endl;
}
};
int main() {
Student s1;
s1.name = "Alice";
s1.age = 20;
s1.score = 92.5;
s1.introduce();
s1.study();
return 0;
}
输出:
我叫 Alice,今年 20 岁。
Alice 正在学习...
3. 访问权限控制*
C++ 的类有三个访问权限:public(公有)、private(私有)、protected(保护)。
(1) 3.1 public vs private*
| 权限 | 类外部能访问吗? | 用途 |
|---|---|---|
| public | ✅ 能 | 对外接口(让外界能用) |
| private | ❌ 不能 | 内部实现(隐藏细节) |
示例:
#include <iostream>
#include <string>
class Student {
private:
std::string name; // private member
int age;
public:
// public setter and getter
void setName(const std::string& n) {
name = n;
}
std::string getName() {
return name;
}
};
int main() {
Student s1;
// s1.name = "Alice"; // ERROR: name is private
s1.setName("Alice"); // OK: access via public function
std::cout << s1.getName() << std::endl;
return 0;
}
💡 封装思想: 把属性设为 private,通过 public 的 setter/getter 访问——这样能控制访问逻辑(如检查年龄是否为负)。
4. 构造函数(Constructor)*
(1) 4.1 什么是构造函数?
构造函数是类里的一个特殊函数——创建对象时自动调用。
| 特点 | 说明 |
|---|---|
| 函数名 | 和类名一样 |
| 无返回值 | 连 void 都不写 |
| 自动调用 | 创建对象时自动执行 |
▶ 示例 2:定义构造函数(难度⭐⭐)
#include <iostream>
#include <string>
class Student {
private:
std::string name;
int age;
public:
// constructor
Student(const std::string& n, int a) {
name = n;
age = a;
std::cout << "Student 对象已创建:" << name << std::endl;
}
void introduce() {
std::cout << "我叫 " << name << ",今年 " << age << " 岁。" << std::endl;
}
};
int main() {
Student s1("Alice", 20); // OK: constructor called automatically when creating object
s1.introduce();
return 0;
}
输出:
Student 对象已创建:Alice
我叫 Alice,今年 20 岁。
5. 析构函数(Destructor)*
(1) 5.1 什么是析构函数?
析构函数是类里的另一个特殊函数——对象销毁时自动调用(如函数结束时、delete 时)。
| 特点 | 说明 |
|---|---|
| 函数名 | ~类名 |
| 无返回值 | 连 void 都不写 |
| 无参数 | 不能接收参数 |
| 自动调用 | 对象销毁时自动执行 |
▶ 示例 3:定义析构函数(难度⭐⭐)
#include <iostream>
#include <string>
class Student {
private:
std::string name;
public:
// constructor
Student(const std::string& n) {
name = n;
std::cout << "构造函数:" << name << " 已创建" << std::endl;
}
// destructor
~Student() {
std::cout << "析构函数:" << name << " 已销毁" << std::endl;
}
};
int main() {
Student s1("Alice"); // call constructor
// when main() ends, s1 is destroyed, destructor is called
return 0;
}
输出:
构造函数:Alice 已创建
析构函数:Alice 已销毁
💡 用途: 在析构函数里释放资源(如关闭文件、释放动态内存)。
6. this 指针*
(1) 6.1 什么是 this 指针?
this 是一个指向当前对象的指针——在成员函数里,this 可以用来访问当前对象。
▶ 示例 4:用 this 区分同名参数(难度⭐⭐)
#include <iostream>
#include <string>
class Student {
private:
std::string name;
public:
void setName(const std::string& name) { // WARNING: parameter name same as member variable
this->name = name; // OK: use this-> to access member variable
}
std::string getName() {
return this->name; // OK: this-> can be omitted (recommended to omit)
}
};
int main() {
Student s1;
s1.setName("Alice");
std::cout << s1.getName() << std::endl;
return 0;
}
输出:
Alice
💡 提示: 如果参数名和成员变量名不一样,可以不用 this->(推荐省略,代码更简洁)。
7. 实战:简单的银行账户类*
▶ 示例 5:BankAccount 类(难度⭐⭐⭐)
#include <iostream>
#include <string>
#include <iomanip>
class BankAccount {
private:
std::string owner;
double balance;
public:
// constructor
BankAccount(const std::string& o, double initialBalance) {
owner = o;
if (initialBalance >= 0) {
balance = initialBalance;
} else {
balance = 0.0;
std::cout << "⚠️ 初始余额不能为负,已设为 0" << std::endl;
}
}
// deposit
void deposit(double amount) {
if (amount > 0) {
balance += amount;
std::cout << "存款成功!+" << amount << std::endl;
} else {
std::cout << "⚠️ 存款金额必须大于 0" << std::endl;
}
}
// withdraw
void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
std::cout << "取款成功!-" << amount << std::endl;
} else if (amount <= 0) {
std::cout << "⚠️ 取款金额必须大于 0" << std::endl;
} else {
std::cout << "⚠️ 余额不足" << std::endl;
}
}
// query balance
void queryBalance() {
std::cout << std::fixed << std::setprecision(2);
std::cout << "账户余额:" << balance << " 元" << std::endl;
}
};
int main() {
BankAccount account("MOTO", 1000.0);
account.queryBalance();
account.deposit(500.0);
account.queryBalance();
account.withdraw(200.0);
account.queryBalance();
account.withdraw(2000.0); // insufficient balance
return 0;
}
输出:
账户余额:1000.00 元
存款成功!+500.00
账户余额:1500.00 元
取款成功!-200.00
账户余额:1300.00 元
⚠️ 余额不足
运行效果:
账户余额:1000.00 元
存款成功!+500.00
账户余额:1500.00 元
取款成功!-200.00
账户余额:1300.00 元
⚠️ 余额不足
❓ 常见问题
📖 小节
- 类:将数据和操作封装在一起
- 对象是类的实例,通过 . 或 -> 访问成员
- 访问修饰符:public/protected/private
- 成员函数在类内声明,可类内或类外定义
- 构造函数:对象创建时自动调用,用于初始化
📝 作业
-
基础题 (Difficulty ⭐): 定义一个
Book类,包含书名、作者、价格三个私有成员。 -
提供公有的 setter 和 getter
-
在
main里创建两个Book对象并输出信息 -
进阶题 (Difficulty ⭐⭐): 定义一个
Rectangle类,包含宽度和高度两个私有成员。 -
提供构造函数(带参数)
-
提供
double getArea()和double getPerimeter()成员函数 -
在
main里测试 -
挑战题 (Difficulty ⭐⭐⭐): 定义一个
Date类,包含年、月、日三个私有成员。 -
提供构造函数(带参数)
-
提供
bool isValid()成员函数(判断日期是否合法) -
提供
void print()成员函数(输出日期,格式:2024-02-29) -
在
main里测试
8. 🚀 下一步*
学会了类与对象的基础,接下来我们学习 构造函数进阶(第29课)—— 默认构造函数、拷贝构造函数、移动语义(C++11 新特性)!