Appearance
🧩10. 类和对象
经过
string的学习,实际上已经接触过类和对象的概念——string本身就是一个类。
1. 为什么需要类?
回顾此前学习的数据类型:
| 类型 | 存储内容 | 支持的操作 |
|---|---|---|
int | 整数 | 算术运算 |
double | 浮点数 | 算术运算 |
char[] | 字符串 | 需借助 strlen、strcpy 等函数 |
以上类型存在一个共同缺陷:数据与其操作函数是分离的。
以描述"学生"为例:
cpp
string name = "小明";
int age = 10;
int score = 95;
// 需自行编写打印函数:
void printStudent(string name, int age, int score) {
cout << name << " " << age << "岁 " << score << "分" << endl;
}当学生数量增多时,数据散落在各个独立变量中,管理和维护将变得困难。
类(class) 正是为了解决这一问题而设计的——将数据及其操作封装为一个整体。
2. 类与对象的基本概念
可以将类与对象的关系理解为模板与实例的关系:
类(class) :定义了数据结构和行为的抽象模板 对象(object) :根据类模板创建的具体实例
例如:
类 对象
┌────────────────────┐ ┌────────────────────┐
│ 住宅设计图 │ 实例化 │ 住宅 A(我家) │
│ - 面积: 100㎡ │ ──────→ │ - 面积: 100㎡ │
│ - 层数: 2层 │ │ - 层数: 2层 │
│ + 开门() │ │ + 开门() │
│ + 开灯() │ │ + 开灯() │
└────────────────────┘ └────────────────────┘
┌────────────────────┐
│ 住宅 B(邻居) │
│ - 面积: 80㎡ │
│ - 层数: 1层 │
│ + 开门() │
│ + 开灯() │
└────────────────────┘同一份类模板可以创建多个不同的对象实例——一个类可以实例化出多个对象。
3. 类的定义
cpp
class Student { // 关键字 class 后跟类名
public: // 访问说明符:公开成员
// ── 成员变量(属性) ──
string name;
int age;
int score;
// ── 成员函数(方法) ──
void print() {
cout << name << " " << age << "岁 " << score << "分" << endl;
}
}; // 类定义结束后须加分号
public:表示其后的成员具有公开访问权限,类外部可直接访问。另有private:(私有权限,仅类内部可访问),后续章节会详细说明。
4. 对象的创建
cpp
int main() {
Student s1; // 创建对象,语法与声明变量类似
s1.name = "小明"; // 为成员变量赋值
s1.age = 10;
s1.score = 95;
s1.print(); // 调用成员函数 → "小明 10岁 95分"
Student s2; // 创建第二个对象
s2.name = "小红";
s2.age = 11;
s2.score = 100;
s2.print(); // → "小红 11岁 100分"
return 0;
}由此可见,数据与操作数据的函数被封装在一起,每个对象独立管理自身数据,结构清晰。
5. 构造函数
每次创建对象后逐一手动赋值较为繁琐。C++ 提供了构造函数(constructor) 机制,使对象在创建时即可自动完成初始化:
cpp
class Student {
public:
string name;
int age;
int score;
// 构造函数:名称与类名相同,无返回值类型
Student(string n, int a, int s) {
name = n;
age = a;
score = s;
}
void print() {
cout << name << " " << age << "岁 " << score << "分" << endl;
}
};
int main() {
Student s1("小明", 10, 95); // 创建时直接传入参数
Student s2("小红", 11, 100);
s1.print();
s2.print();
return 0;
}构造函数在对象创建时自动调用,确保每个对象初始化完毕即可使用。
默认构造函数
若未定义任何构造函数,C++ 会隐式提供一个默认构造函数,该函数不执行任何初始化操作:
cpp
class Student {
public:
string name;
int age;
};
Student s; // 可通过默认构造函数创建,但 name 和 age 未初始化然而,一旦用户自定义了任一构造函数,默认构造函数即被覆盖。若仍需支持无参构造,须显式定义:
cpp
class Student {
public:
Student() {} // 显式定义无参构造函数
Student(string n, int a) { // 有参构造函数
name = n;
age = a;
}
string name;
int age;
};
Student s1; // 使用无参构造函数
Student s2("小明", 10); // 使用有参构造函数6. 回顾 string —— 类与对象的实际应用
重新审视 string,可以更清晰地理解类与对象的概念:
cpp
string s = "Hello";
int len = s.length(); // 调用成员函数
string sub = s.substr(0, 3); // 调用成员函数string是一个类,s是该类的一个对象length()、substr()、find()等均为成员函数- 字符串内部的字符数据、长度信息等属于成员变量
+运算符之所以能直接拼接字符串,是因为类内部对运算符进行了重载
至此可以理解为何 string 比 char[] 更方便——因为它是一个封装完善的类,自带了所有常用操作。
TIP
这正是面向对象编程的核心思想:将数据与操作封装在一起,提升代码的清晰性、安全性和可维护性。
7. 总结
| 概念 | 说明 | 类比 |
|---|---|---|
| 类(class) | 定义数据结构和行为的抽象模板 | 建筑设计图 |
| 对象(object) | 根据类创建的具体实例 | 按图纸建造的实体建筑 |
| 成员变量 | 类中定义的变量,描述对象的属性 | 建筑的面积、层数 |
| 成员函数 | 类中定义的函数,描述对象的行为 | 开门、开灯等操作 |
| 构造函数 | 对象创建时自动调用的初始化函数 | 交房时已完成的基础装修 |
类与对象是 C++ 的核心概念,也是面向对象编程的基础。后续将继续深入学习封装、继承、多态等进阶特性。掌握当前内容后,已可使用类来组织代码结构。
🧠 8. 练习题
定义一个
Book类,包含title(书名)、author(作者)和price(价格)三个成员变量,以及一个print()成员函数用于输出书籍信息。创建两本书的对象并调用print()。定义一个
Circle类,包含一个成员变量radius(半径),以及两个成员函数:area()计算面积(πr²),perimeter()计算周长(2πr)。创建一个半径为 5 的圆对象,输出它的面积和周长。定义一个
Counter类,包含一个私有的count成员变量(初始为 0),以及increment()(加1)、decrement()(减1)和getCount()(获取当前值)三个成员函数。创建一个计数器对象,加3次,减1次,输出最终结果。为
Book类添加一个构造函数,创建对象时直接传入书名、作者和价格。创建三个不同的 Book 对象并输出。定义一个
Temperature类,包含一个celsius成员变量,以及toFahrenheit()成员函数(返回摄氏度转华氏度的结果,公式:F = C × 9/5 + 32)。创建几个不同温度的对象并输出对应的华氏度。定义一个
Rectangle类,包含长和宽,以及isSquare()成员函数判断是否为正方形。测试几个不同的矩形。定义一个
Student类,包含姓名和三个科目的成绩,添加一个average()成员函数计算平均分。创建几个学生对象,输出他们的平均分。