内容参考于《抽象接口技术和组件开发规范及其思想》
三.多态
所谓多态,其字面含义就是具有“多种形式”。从调用者的角度看对象,会发现它们非常相似,难以区分,但是这些被调用对象的内部处理实际上却各不相同。 换句话说,各个对象虽然内部处理不同,但对于使用者(调用者)来讲,们却是相同的。
1. 示例1:(不是最终解)
一个学生类,自我介绍的不同,可以表现为多态。
student.h
#ifndef __STUDENT_H
#define __STUDENT_H
struct student {
int(*student_self_introduction) (struct student *p_student);
char name[10]; /* 姓名 (假定最长 10 字符) */
unsigned int id; /* 学号 */
char sex; /* 性别:'M',男; 'F' ,女 */
float height; /* 身高 */
float weight; /* 体重 */
};
int student_init(struct student *p_student,
char *p_name,
unsigned int id,
char sex,
float height,
float weight,
int(*student_self_introduction) (struct student *));
/* 学生类提供的自我介绍方法 */
static inline
int student_self_introduction(struct student *p_student)
{
return p_student->student_self_introduction(p_student);
}
#endif
student.c
#include "student.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
int student_init(struct student *p_student,
char *p_name,
unsigned int id,
char sex,
float height,
float weight,
int(*student_self_introduction) (struct student *));
{
memcpy(p_student->name, p_name, strlen(p_name));
p_student->id = id;
p_student->sex = sex;
p_student->height = height;
p_student->weight = weight;
p_student->student_self_introduction = student_self_introduction;
return 0;
}
main.c
static int student_zhangsan_introduction(struct student *p_student)
{
const char *str = "亲爱的老师,同学们,我叫张三,来自美丽的四川,今年 18 岁, "
"是一个自信,开朗,友好,积极向上的人,我有着广泛的兴趣爱"
"好,喜欢健身、打篮球、看书、下棋、听音乐,特别对主持和街"
"舞有着浓厚的兴趣,希望能和同学们做好朋友,一起学习,一起"
"玩耍……";
printf("%s\n", str);
return 0;
}
static void first_class(struct student *p_students, int num)
{
int i;
for (i = 0; i < num; i++) {
student_self_introduction(&p_students[i]);
}
}
int main()
{
struct student student[50];
/* 根据每个学生的信息,依次创建各个学生对象 */
student_init(&student[0], "zhangsan", 2010447222, 'M', 173, 60, student_zhangsan_introduction);
// ...
/* 上第一节课 */
first_class(student, 50);
}
- 多态的核心是:对于上层调用者,不同的对象可以使用完全相同的操作方法,但是每个对象可以有各自不同的实现方式。
- 虽然函数指针同属性一样,放在结构体类型的定义中,但函数指针不能视为普通的属性,其应视为一种方法(是被用来调用的),在面向对象编程中,通常将类中的函数指针称之为抽象方法(因其在定义类时没有实现, 所以是“抽象” 的)。此外,往往还会将函数指针封装到抽象类(最终解)中。
2. 示例2:
标准输出输出的框架
file.h
struct FILE {
void(*open) (char *name, int mode);
void(*close) ();
int(*read) ();
void(*write) ();
void(*seek) (long index, int mode);
};
console.c
#include "file.h"
static void open(char *name, int mode)
{
// 实现代码
}
static void close()
{
// 实现代码
}
static int read()
{
// 实现代码
}
static void write()
{
// 实现代码
}
static void seek(long index, int mode)
{
// 实现代码
}
struct FILE console = { open, close, read, write, seek };
main.c
exttern struct FILE console;
struct FILE * STDOUT = &console;
// 对于printf
void putchar (char c)
{
STDOUT->write(&c, 1);
}