在之前的章节当中,我们在编写程序时,通常采用以下步骤:
- 将问题的解法分解成若干步骤
- 使用函数分别实现这些步骤
- 依次调用这些函数
这种编程风格的被称作面向过程。除了面向过程之外,还有一种被称作面向对象的编程风格被广泛使用。面向对象采用基于对象的概念建立模型,对现实世界进行模拟,从而完成对问题的解决。
C语言的语法并不直接支持面向对象风格的编程。但是,我们可以通过额外的代码,让C语言实现一些面向对象特性。在这一节当中,我们将探究什么是面向对象,以及怎样用C语言来实现它。
单纯理论上的讨论可能比较难以理解,为了能够让我们的讨论能够落地到实际中,我们选取学校为场景,展开对面向对象风格编程的讨论。
一般而言面向对象风格的编程具有以下3大特性:
- 封装
- 继承
- 多态
我们将以这3个特性为线索,讨论C语言如何面向对象编程。
1. 封装
我们来看看学校里面最重要的主体是什么?是学生。学生肯定拥有很多属性,比如学生的学号、姓名、性别、考试分数等等。自然地,我们会声明一个结构体用于表示学生。
struct student {
int id; // 学号
char name[20]; // 姓名
int gender; // 性别
int mark; // 成绩
};
学生的学号由入学年份
、班级
、序号
拼接构成。
例如,某一个同学的是2022
年入学的123
班的26
号学生。那么,它的学号为202212326
。
为了方便设置学号,我们有一个makeStudentId
函数,参数为入学年份
、班级
、序号
,它将这些数据拼接成字符串,再将字符串转换为整型数据,最后将这个整型数据作为学生的id
并返回。
int makeStudentId(int year, int classNum, int serialNum)
{
char buffer[20];
sprintf(buffer, "%d%d%d", year, classNum, serialNum);
int id = atoi(buffer);
return id;
}
sprintf
函数在第21节课《让熊跑起来》中有讲过,它和printf
函数类似,printf
函数会将占位符"%d%d%d"
替换为其后的参数,将结果打印到控制台上。而sprintf
不会将结果打印在控制台上,而是将结果存放在第一个参数buffer
所指示的字符数组当中。
函数atoi
能将buffer
指示的字符串转换为整型并返回结果。
性别在结构体中存储为整型数值,0
代表女生、1
代表男生。而显示时,我们希望0
显示为女
,1
显示为男
。因此,还需要有一对用于操作性别的函数。在函数命名中,使用numGender
代表使用整型表示的性别。strGender
代表使用字符串表示的性别。
我们将定义两个函数:
numGenderToStrGender
表示,将整型表示的性别转换为字符串表示的性别。
strGenderToNumGender
表示,将字符串表示的性别转换为整型表示的性别。
const char *numGenderToStrGender(int numGender)
{
if (numGender == 0)
{
return "女";
}
else if (numGender == 1)
{
return "男";
}
return "未知";
}
int strGenderToNumGender(const char* strGender)
{
int numGender;
if (strcmp("男", strGender) == 0)
{
numGender = 1;
}
else if (strcmp("女", strGender) == 0)
{
numGender = 0;
}
else
{
numGender = -1;
}
return numGender;
}
我们将使用以下方式,调用这个结构体和这3个函数。
int main()
{
struct student stu;
// 设置数值
// 学号:202212326
// 姓名:小明
// 性别: 男
// 成绩:98
stu.id = makeStudentId(2022, 123, 26);
strcpy(stu.name, "小明");
stu.gender = strGenderToNumGender("男");
stu.mark = 98;
// 打印这些数值
printf("学号:%d\n", stu.id);
printf("姓名:%s\n", stu.name);
const char* gender = numGenderToStrGender(stu.gender);
printf("性别:%s\n", gender);
printf("分数:%d\n", stu.mark);
return 0;
}