1.0 面向对象编程思维
在面向对象风格中,结构体被看做数据(data),而操作数据的函数称作方法(method)。目前函数 和数据是分离的,函数并不直接操作数据,我们需要拿到函数返回的结果,再将其赋值给数据。面向对 象风格编程的第一大特性---封装,它希望方法直接操作数据,并且将数据和方法结合在一起,它们构成 一个整体。而这个整体被称作对象。
设置数据函数的命名方法和获取数据函数的命名方法:
一般来说,获取数据的方法会被命名为 getXXX ,设置数据的方法 会被命名为 setXXX
将函数的第一个参数设置为 struct student * ,让函数直接操作 student 结构体。
修改函数名,获取数据的方法命名为 getXXX ,设置数据的方法命名为 setXXX 。
typedef struct STRUCT // 结构体被看做是数据
{int id;char name[20];int gender;int mark;
} Student_t;
在面向对象的编程风格中结构体被看做是数据,结构体中有结构体成员变量
void setStudentId(Student_t *s, int year, int classNum, int serialNum)
{char buffer[20];sprintf(buffer, "%d%d%d", year, classNum, serialNum);int id = atoi(buffer);s->id = id;
}
以下的程序基本将结构体指针,作为一个参数传递进来
const char *getGender(Student_t *s)
{if (s->gender == 0){return "女";}else if (s->gender == 1){return "男";}return "未知";
}
void setGender(Student_t *s, const char *strGender)
{int numGender;if (strcmp("男", strGender) == 0){numGender = 1;}else if (strcmp("女", strGender) == 0){numGender = 0;}else{numGender = -1;}s->gender = numGender;
}
主函数调用:
int main(void)
{Student_t stu;// 参数调用setStudentId(&stu, 2020, 123, 25);strcpy(stu.name, "小明");setGender(&stu, "男");stu.mark = 98;// 打印这些数值printf("学号:%d\n", stu.id);printf("姓名:%s\n", stu.name);// 结构体指针,获取到的是结构体的地址const char *gender = getGender(&stu);printf("性别:%s\n", gender);printf("分数:%d\n", stu.mark);return 0;
}
目前,函数可以直接操作数据了。但是,函数和数据依然是两个独立的部分。我们要将函数和数据结合到一起,这样,这个整体就能被称作对象,函数可以称作属于这个对象的方法
大多数面向对象语言都提供了以下的格式调用一个对象的方法
对象.方法(对象指针,参数1,参数2, 参数3...)
stu.setGender(&stu, "男");
以上代码中,对象为 stu ,方法为 setGender 。通过对象 + 点 + 方法的形式,可以调用属于对 象 stu 的 setGender 方法。在方法的参数中传入性别 男 。这样,方法会把性别 男 转换为整形,并设置 到对象 stu 的数据当中。
在C语言中,若要实现对象 + 点 + 方法的形式,我们可以借助于函数指针
在结构中,声明这3个函数的函数指针:
typedef struct STRUCT // 结构体被看做是数据
{void (*setStudentId)(struct student *s, int year, int classNum, int serialNum);const char *(*getGender)(struct student *s);void (*setGender)(struct student *s, const char *strGender);int id;char name[20];int gender;int mark;
} Student_t;
为了让函数指针有正确的指向,我们需要通过一个 initStudent 函数,为结构体初始化。
void setStudentId(Student_t *s, int year, int classNum, int serialNum)
{char buffer[20];sprintf(buffer, "%d%d%d", year, classNum, serialNum);int id = atoi(buffer);s->id = id;
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>typedef struct STRUCT // 结构体被看做是数据
{int id;char name[20];int gender;int mark;void (*setStudentId)(struct STRUCT* s, int year, int classNum, int serialNum);const char* (*getGender)(struct STRUCT* s);void (*setGender)(struct STRUCT* s, const char* strGender);
} Student_t;void setStudentId(Student_t* s, int year, int classNum, int serialNum)
{char buffer[20];sprintf(buffer, "%d%d%d", year, classNum, serialNum);int id = atoi(buffer);s->id = id;
}const char* getGender(Student_t* s)
{if (s->gender == 0){return "女";}else if (s->gender == 1){return "男";}return "未知";
}void setGender(Student_t* s, const char* strGender)
{int numGender;if (strcmp("男", strGender) == 0){numGender = 1;}else if (strcmp("女", strGender) == 0){numGender = 0;}else{numGender = -1;}s->gender = numGender;
}void InitStudent(Student_t* s)
{s->setStudentId = setStudentId;s->getGender = getGender;s->setGender = setGender;
}int main(void)
{#if 0Student_t stu;// 参数调用setStudentId(&stu, 2020, 123, 25);strcpy(stu.name, "小明");setGender(&stu, "男");stu.mark = 98;// 打印这些数值printf("学号:%d\n", stu.id);printf("姓名:%s\n", stu.name);// 结构体指针,获取到的是结构体的地址const char* gender = getGender(&stu);printf("性别:%s\n", gender);printf("分数:%d\n", stu.mark);return 0;
#elseStudent_t stu;InitStudent(&stu);stu.setStudentId(&stu, 2022, 123, 26);strcpy(stu.name, "小明");stu.setGender(&stu, "男");stu.mark = 98;printf("学号:%d\n", stu.id);printf("姓名:%s\n", stu.name);const char* gender = stu.getGender(&stu);printf("性别:%s\n", gender);printf("分数:%d\n", stu.mark);return 0;
#endif}
运行以上程序输出如下结果: