【GESP】C++六级考试大纲知识点梳理, (6) 面向对象编程(OOP)基础
GESP C++六级官方考试大纲中,第6条考点标志着我们编程思维的一次重要跃迁——从“面向过程”转向“面向对象”。
(6)掌握面向对象的思想,了解封装、继承、多态的基本概念,并掌握类的创建和基本的使用方法。
本人也是边学、边实验、边总结,且对考纲深度和广度的把握属于个人理解。因此本文更多的不是一个教程,而是个人知识梳理,如有遗漏、疏忽,欢迎指正、交流。
面向对象编程(Object-Oriented Programming,简称 OOP)听起来很高大上,其实它最贴近我们的真实世界。如果说“面向过程”是像做菜一样一步步按照食谱执行,那么“面向对象”就是组装一台精密的机器,每个零件(对象)都有自己的功能,组合起来完成复杂的任务。对于初学者来说,理解“类”与“对象”的关系是关键。
六级考点系列:
一、什么是面向对象 (OOP)?
在学习 C++ 的前几个级别时,我们写的代码大多是面向过程 (Procedure Oriented) 的。 比如解决“把大象装进冰箱”这个问题,面向过程的思维是:
- 打开冰箱门();
- 拿起大象();
- 塞进冰箱();
- 关闭冰箱门();
我们关注的是动作(函数) 的执行顺序。
而面向对象 (Object Oriented) 的思维则是:我们需要两个“对象”:大象 和 冰箱。
- 冰箱这个对象,应该具备“开门”、“关门”、“装东西”的功能。
- 大象这个对象,应该具备“移动”、“体积”等属性。
然后我们指挥对象工作:
冰箱.打开() -> 冰箱.装入(大象) -> 冰箱.关闭()。
核心区别:
- 面向过程:关注怎么做(Step by Step)。适合简单逻辑。
- 面向对象:关注谁来做(Who does what)。适合复杂系统,方便管理和扩展。
二、类 (Class) 与 对象 (Object)
这是 OOP 中最核心的一对概念,一定要区分清楚。
2.1 概念比喻
- 类 (Class):是图纸、是模具。它规定了某一类事物应该长什么样(属性),能干什么(方法)。它是一个抽象的概念,不占用内存空间。
- 对象 (Object):是房子、是饼干。它是根据图纸造出来的实物,是模具印出来的成品。它是具体的,占用内存空间。
例子:
- “人类”是一个类(Class)。
- “坐在你旁边的那个叫小明的同学”是一个对象(Object)。
2.2 面向对象的语法总结
在 C++ 中定义和使用类,我们会用到一些核心的关键字和符号:
| 关键字/符号 | 作用 | 示例 |
|---|---|---|
class | 定义一个类(模具)。 | class Student { ... }; |
public: | 访问权限修饰符,表示其后的成员是公开的,外部可以直接访问。 | public: string name; |
private: | 访问权限修饰符,表示其后的成员是私有的,只有类内部才能访问。 | private: int password; |
string, int 等 | 定义成员变量(属性)的数据类型。 | string name; |
void | 定义成员函数(方法)的返回值类型。 | void introduce() { ... }; |
. (点操作符) | 用来访问对象的属性或调用对象的方法。 | stu1.name = "小明"; |
:: (作用域解析符) | 用于在类外部定义成员函数,或访问命名空间成员。 | void Student::introduce() { ... }; (类外定义方法) \ std::cout (访问命名空间 std 中的 cout 对象) |
注意:在调用对象的普通(非静态)方法时,我们使用 . (点操作符),例如 stu1.introduce();。作用域解析符 :: 主要用于类外部定义成员函数,或者访问特定命名空间中的成员(比如 std::cout 中的 std 就是一个命名空间)。
2.2.1 类定义语法模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class ClassName {
private:
// 私有属性(数据),只能在类内部访问
DataType privateMember1;
DataType privateMember2;
public:
// 公有属性(数据),外部可直接访问,但通常不建议
DataType publicMember1;
// 构造函数:对象创建时自动调用,用于初始化
ClassName(ParameterType param1, ...) {
// 初始化成员变量
}
// 析构函数:对象销毁时自动调用,用于清理资源
~ClassName() {
// 清理工作
}
// 公有方法(函数),外部可调用,实现类的行为
ReturnType publicMethod1(ParameterType param1, ...) {
// 方法实现
return value;
}
// 私有方法(函数),只能在类内部调用,辅助实现公有方法
private:
ReturnType privateMethod1(...) {
// 方法实现
}
};
2.3 C++ 代码实现
在 C++ 中,我们用 class 关键字来定义类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <string>
using namespace std;
// 1. 定义一个类:Student (学生)
class Student {
public: // 访问权限:公开的
// --- 属性 (成员变量) ---
string name;
int age;
int score;
// --- 行为 (成员函数) ---
void introduce(); // 声明:方法原型,实现在类外部
void study() {
score++;
cout << name << "正在努力学习,分数+1,现在分数是:" << score << endl;
}
};
// 在类外部使用作用域解析符 :: 实现 introduce 方法
void Student::introduce() {
cout << "大家好,我是" << name << ",今年" << age << "岁。" << endl;
}
int main() {
// 2. 创建对象 (实例化)
Student stu1; // 创建了一个叫 stu1 的对象
// 3. 使用对象 (访问属性和方法)
stu1.name = "小明";
stu1.age = 13;
stu1.score = 90;
stu1.introduce(); // 调用方法
stu1.study(); // 调用方法
// 创建另一个对象
Student stu2;
stu2.name = "小红";
stu2.introduce(); // 小红和小明互不干扰
return 0;
}
三、OOP 三大特性
考试大纲明确要求了解:封装、继承、多态。
3.1 封装 (Encapsulation)
含义:把数据(属性)和操作数据的方法(函数)捆绑在一起,并且隐藏内部实现的细节,只暴露必要的接口给外部使用。
比喻:就像电视机。
- 隐藏细节:你看不见里面的电路板、显像管(这就是
private私有成员)。你也不能直接用手去拨动里面的电线,否则会触电或弄坏电视。 - 暴露接口:电视机提供了遥控器和按钮(这就是
public公有成员)。你只需要按“开机”、“换台”,不需要知道电路是怎么工作的。
C++ 关键字:
public(公有):谁都能访问。private(私有):只有类自己内部能访问,外部(main函数里)不能直接改。protected(保护):主要用于继承,子类能访问。
为什么要封装? 安全!防止外部代码随意篡改对象内部的敏感数据。
3.2 继承 (Inheritance)
含义:允许一个新的类(子类/派生类)获取现有类(父类/基类)的属性和方法。
比喻:
爸爸(父类)有亿万家产(属性)和经商技巧(方法)。 儿子(子类)继承了爸爸,天生就有了家产和技巧,不用从头开始奋斗。同时,儿子还可以有自己独特的爱好(扩展新功能)。
3.2.1 继承的语法规则
在 C++ 中,使用 : 符号来表示继承关系。基本语法如下:
1
2
3
class 子类名 : 访问修饰符 父类名 {
// 子类特有的属性和方法
};
子类名:正在定义的新的类。访问修饰符:指定继承方式,可以是public、protected或private。public继承 (最常用):父类的public成员在子类中依然是public;父类的protected成员在子类中依然是protected。父类的private成员子类不能直接访问。protected继承:父类的public和protected成员在子类中都变为protected。private继承:父类的public和protected成员在子类中都变为private。
父类名:被继承的那个类。
简单来说,考试中我们通常使用 public 继承,它表示“儿子”完全公开地继承“爸爸”的衣钵,该公开的还是公开,该保护的还是保护。
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 父类:动物
class Animal {
public:
string name;
void eat() {
cout << name << " 正在吃东西..." << endl;
}
};
// 子类:狗 (继承自 Animal)
class Dog : public Animal {
public:
void bark() { // 子类特有的方法
cout << "汪汪汪!" << endl;
}
};
int main() {
Dog myDog;
myDog.name = "旺财";
myDog.eat(); // 继承自父类的方法,可以直接用!
myDog.bark(); // 自己的方法
return 0;
}
3.3 多态 (Polymorphism)
含义:同一个操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。简单说就是 “多种形态”。
比喻:不管是理发师、厨师还是园丁,都有一个动作叫 “Cut (切/剪)”。
- 对理发师说“Cut” -> 他会剪头发。
- 对厨师说“Cut” -> 他会切菜。
- 对园丁说“Cut” -> 他会修剪草坪。
同一个命令,不同的人(对象)做出了不同的反应,这就是多态。
在 C++ 中,多态通常通过虚函数 (virtual function) 来实现。当父类的指针指向子类对象时,调用同一个函数,会执行子类特定的版本。
注:六级考试对多态的要求通常是“了解概念”,具体的虚函数语法和动态绑定机制可能在更高级别深入考察,但理解其思想对于设计程序非常有帮助。
四、构造函数与析构函数
这是类中两个特殊的函数,就像人的“出生”和“去世”。
4.1 构造函数 (Constructor)
- 函数名:与类名完全相同。
- 返回值:没有返回值(连
void都不写)。 - 时机:对象被创建时自动调用。
- 作用:初始化。给对象的属性赋初值,比如刚买的手机电量默认是 100%。
4.2 析构函数 (Destructor)
- 函数名:
~+ 类名(比如~Student)。 - 返回值:没有返回值。
- 时机:对象被销毁时(比如函数结束,局部变量失效时)自动调用。
- 作用:清理善后。比如释放申请的内存,关闭打开的文件等。
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <string>
using namespace std;
class Hero {
public:
string name;
// 构造函数
Hero(string n) {
name = n;
cout << name << " 英雄降临!(构造函数被调用)" << endl;
}
// 析构函数
~Hero() { cout << name << " 英雄牺牲了... (析构函数被调用)" << endl; }
};
int main() {
{
Hero h1("盖伦"); // 创建对象,输出:盖伦 英雄降临!
} // 出了这个大括号,h1 作用域结束,对象销毁, // 输出:盖伦 英雄牺牲了...
cout << "----" << endl;
return 0;
}
输出:
1
2
3
盖伦 英雄降临!(构造函数被调用)
盖伦 英雄牺牲了... (析构函数被调用)
----
五、备考总结
对于 GESP 六级考生,面向对象部分重点掌握以下几点:
- 语法层面:
- 熟练掌握
class的定义。 - 会定义成员变量和成员函数。
- 理解
public和private的区别。 - 会编写简单的构造函数进行初始化。
- 会实例化对象并调用其成员 (
.操作符)。
- 熟练掌握
- 概念层面:
- 能够用自己的话解释“封装、继承、多态”。
- 理解“类是图纸,对象是实物”。
- 结构体 vs 类:
- 在 C++ 中,
struct和class极其相似。 - 唯一核心区别:
struct默认权限是public,class默认权限是private。 - 考试中如果遇到简单的属性组合(如坐标点
x, y),用struct依然很方便;但如果涉及到复杂的行为管理,建议尝试用class。
- 在 C++ 中,
面向对象是一种编程世界观,掌握它,你的代码将从“杂乱的脚本”进化为“严密的系统”。加油!
附录:结构体 (struct) 与类 (class) 的异同
这是一个非常经典且在面试和考试中常被问到的问题。在 C++ 中,struct(结构体)和 class(类)的区别既微小又深刻,这主要源于 C++ 的历史包容性。
简而言之:在技术上,它们几乎一模一样;但在设计意图和默认行为上,有两点核心区别。
1. 技术上的区别(语法层面)
在 C++ 中,struct 和 class 的功能几乎是完全等价的。struct 也可以有构造函数、析构函数、成员函数、继承、多态等。
唯一的区别在于默认的访问权限:
| 特性 | struct (结构体) | class (类) |
|---|---|---|
| 成员默认权限 | public (公有) | private (私有) |
| 继承默认权限 | public (公有继承) | private (私有继承) |
代码对比:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct A {
int x; // 默认为 public
};
class B {
int y; // 默认为 private
};
int main() {
A a;
a.x = 10; // ✅ OK,外部可以直接访问
B b;
// b.y = 10; // ❌ Error,y 是私有的,不可访问
// 如果要访问 private 成员,需要通过 public 方法
return 0;
}
2. 为什么要设计两种模式?(历史与设计哲学)
既然功能一样,为什么不直接废除 struct 或者只用 class 呢?这主要归功于 C++ 之父 Bjarne Stroustrup 的设计哲学:“不破坏现有的代码” (Backward Compatibility)。
A. 兼容 C 语言 (C Compatibility)
C++ 被设计为 C 语言的超集。
- 在 C 语言中,
struct只是一个数据的集合,所有成员天然都是公开的(没有 private 的概念)。 - 为了让数百万行现有的 C 代码能在 C++ 编译器下直接编译通过,C++ 中的
struct必须保持“默认公有”这一特性。如果改成默认私有,所有的 C 程序都会报错。
B. 强调面向对象封装 (Encapsulation)
- 引入
class是为了支持面向对象编程 (OOP)。 - OOP 的核心原则之一是封装——即默认隐藏内部细节,只暴露接口。
- 因此,
class采用了“默认私有”的策略,这是一种防御性编程的思维:除非你明确说这个是可以公开的,否则它就是安全的、隐藏的。
3. 我们该如何选择?(最佳实践)
虽然你可以在 struct 里写复杂的逻辑,也可以在 class 里全写 public,但为了代码的可读性和规范性,业界通常遵循以下约定:
使用 struct 的场景
- 纯数据集合 (POD - Plain Old Data):仅仅是为了把几个数据捆绑在一起,不包含复杂的逻辑或私有变量。
- 例如:二维坐标点
Point { int x; int y; },颜色Color { int r; int g; int b; }。 - 作为“大号”参数包:函数参数太多时,打包成一个 struct 传递。
使用 class 的场景
- 真正的“对象”:包含数据(属性)和行为(方法)。
- 需要封装:有私有成员,不希望外部直接修改内部数据(例如学生的分数不能随意被随意改为负数,需要通过函数修改)。
- 涉及继承和多态:构建复杂的类层次结构。
总结
- Struct 是为了兼容过去(C语言习惯,数据公开)。
- Class 是为了规范未来(OOP习惯,数据隐藏)。
- 考试中如果只涉及简单的
x, y坐标存储,写struct会省去写public:的麻烦;如果是写一个完整的系统,请使用class。
所有代码已上传至Github:https://github.com/lihongzheshuai/yummy-code
GESP 学习专题站:GESP WIKI
“luogu-”系列题目可在洛谷题库进行在线评测。
“bcqm-”系列题目可在编程启蒙题库进行在线评测。
欢迎加入:Java、C++、Python技术交流QQ群(982860385),大佬免费带队,有问必答
欢迎加入:C++ GESP/CSP认证学习QQ频道,考试资源总结汇总
欢迎加入:C++ GESP/CSP学习交流QQ群(688906745),考试认证学员交流,互帮互助
