一、前言
面向对象编程(OOP)并不是一种特定的语言或者工具,它只是一种设计方法、设计思想;
它表现出来的三个最基本的特性就是封装、继承和多态;
二、封装
概念:封装,就是把数据和方法打包到一个类里;
其实C标准库中的文件操作就用到了面向对象的思想,例如:fopen()、fclose()和fwrite()等函数的操作对象就是FILE;
数据内容就是FILE,fopen()可看做构造函数,fclose()可看做析构函数,数据的读写操作分别是fread()、fwrite();
实例:实现一个单身狗类
/****************************************************************
头文件:single_dog.h
****************************************************************/
#ifndef
#define
typedef struct
{
char* Name; //名字
}Single_dog;
void Single_dog_Constructor(Single_dog* const self, char* Name); //构造函数
void Single_dog_Destructor(Single_dog* self); //析构函数
char* Single_dog_getName(Single_dog const * const self);
#endif
/****************************************************************
源文件:single_dog.c
****************************************************************/
#include "single_dog.h"
#include "string.h"
//构造函数
void Single_dog_Constructor(Single_dog* const self, char* Name)
{
strcpy(self->Name,Name);
}
//析构函数
void Single_dog_Destructor(Single_dog* self)
{
if(self != NULL) {
free(self);
self = NULL;
}
}
//获取属性值函数
char* Single_dog_getName(Single_dog const * const self)
{
return self->Name;
}
/****************************************************************
主文件:main.c
****************************************************************/
#include "single_dog.h"
#include <stdio.h>
int main()
{
Single_dog s1,s2;
Single_dog_Constructor(&s1,"铁柱",6);
Single_dog_Constructor(&s2,"钢蛋",9);
printf("s1(Name=%s)\n",Single_dog_getName(&s1));
printf("s2(Name=%s)\n",Single_dog_getName(&s2));
return 0;
}
三、继承
概念:继承,就是基于现有的一个类去定义一个新类,这样有助于重用代码,更好的组织代码。
在C语言中实现继承也非常简单,只要把基类放到继承类的第一个数据成员
的位置就可以了;
实例:继承单身狗类,实现一个单身“男”狗类
/****************************************************************
头文件:single_dog_male.h
****************************************************************/
#ifndef
#define
#include "single_dog.h"
typedef struct
{
//继承Single_dog
Single_dog super;
//自己的属性
int HandSpeed;
}Single_dog_male;
//构造函数
void Single_dog_male_Constructor(Single_dog_male* const self, char* Name, int HandSpeed);
int Single_dog_male_getHandSpeed(Single_dog_male const * const self);
int Single_dog_male_doNeedlework(Single_dog_male const * const self);
#endif
/****************************************************************
源文件:single_dog_male.c
****************************************************************/
#include "single_dog_male.h"
void Single_dog_male_Constructor(Single_dog_male* const self, char* Name, int HandSpeed)
{
Single_dog_Constructor(&self->super,Name);
self->HandSpeed = HandSpeed;
}
int Single_dog_male_getHandSpeed(Single_dog_male const * const self)
{
return self->HandSpeed;
}
int Single_dog_male_doNeedlework(Single_dog_male const * const self)
{
int time = 0;
//开始做针线活
//结束 time = xxx;
return time;
}
/****************************************************************
主文件:main.c
****************************************************************/
#include "single_dog_male.h"
#include <stdio.h>
int main()
{
Single_dog_male s1,s2;
Single_dog_male_Constructor(&s1,"铁柱",6);
Single_dog_male_Constructor(&s2,"钢蛋",9);
printf("s1(Name=%s,HandSpeed=%d)\n",Single_dog_getName(&s1.super),Single_dog_male_getHandSpeed(&s1));
printf("s2(Name=%s,HandSpeed=%d)\n",Single_dog_getName(&s2.super),Single_dog_male_getHandSpeed(&s2));
printf("s1(针线活时间:%d)\n",Single_dog_male_doNeedlework(s1));
printf("s2(针线活时间:%d)\n",Single_dog_male_doNeedlework(s1));
return 0;
}
四、多态
概念:多态,就是不同的类对同一个信号都能反应,但是做出的反应是不一样的;
实例:有一个抽象基类(接口):动物。
狗和猫都继承自动物,狗和猫都会对叫
这个信号做出反应,但是狗做出的反应是“汪汪汪”,猫做出的反应是“喵喵喵”,这就是多态的意思;
实现流程
- 定义一个接口类,在接口类中定义虚表、虚表指针、虚函数;
- 定义一个实现类,在实现类构造函数中显示的初始化虚表(即将本类的虚函数赋值给虚表中的函数指针),如未显示初始化则会调用接口类中的虚函数,而不会调用实现类中的虚函数;
- 根据功能需求编写实现类的虚函数;
- 在接口类中定义一个统一的对外公共接口,供所有子类对象访问;
接口类(类似于C++中的虚基类)
在接口类中需要定义虚表和虚表指针:
- 虚表(Virtual Table):是这个类所有虚函数的函数指针的集合;
- 虚表指针(Virtual Table Pointer):是一个指向虚表的指针,这个虚表指针必须存在于每个对象实例中,会被所有子类继承;
/****************************************************************
头文件:animal.h
****************************************************************/
#ifndef
#define
#include <stdio.h>
struct Animal_VirtualTable;
typedef struct Animal
{
struct Animal_VirtualTable* Vptr; //虚表指针
int Species; //物种
}Animal;
struct Animal_VirtualTable //虚表
{
void (*Animal_Sound)(Animal const * const me);
};
//操作函数
void Animal_Constrator(Animal* const self, char* Species); //构造函数
static inline void Animal_Sound(Animal const * const self) //对外公共接口
{
(*self->Vptr->Animal_Sound)(self);
}
#endif
/****************************************************************
源文件:animal.c
****************************************************************/
#include "animal.h"
//虚函数
static void Animal_Sound_(Animal const * const self);
void Animal_Constrator(Animal* const self, char* Species)
{
//Animal类的虚表
static struct Animal_VirtualTable const vtbl = { &Animal_Sound_ };
//初始化成员
self->Vptr = &vtbl;
self->Species = Species;
}
static void Animal_Sound_(Animal const * const self)
{
printf("Animal_Sound\n");
}
实现类–Dog
/****************************************************************
头文件:dog.h
****************************************************************/
#ifndef
#define
#include "animal.h"
#include <stdio.h>
#include <string.h>
typedef struct Dog
{
//继承自Animal
Animal super;
//自身属性
int Age;
int Color;
}Dog;
//操作函数
void Dog_Constrator(Dog* const self, int Species,int Age,int Color); //构造函数
#endif
/****************************************************************
源文件:dog.c
****************************************************************/
#include "Dog.h"
//虚函数
static void Dog_Sound_(Animal const * const self);
void Dog_Constrator(Dog* const self, int Species,int Age,int Color)
{
//基类包含 vptr,子类会自动继承,但是,vptr 需要被子类的虚表重新赋值
//创建一个虚表,并指向自身虚函数
static struct Animal_VirtualTable const vtbl = { &Dog_Sound_ };
//初始化父类参数
Animal_Constrator(&self->super,Species);
self->super.Vptr = &vtbl; //初始化虚表指针
//初始化自身参数
self->Age = Age;
self->Color = Color;
}
static void Dog_Sound_(Animal const * const self)
{
Dog const * const self_ = (Dog const *)self;
printf("wang,I'm a dog.\n");
}
实现类–Cat
/****************************************************************
头文件:cat.h
****************************************************************/
#ifndef
#define
#include "animal.h"
#include <stdio.h>
typedef struct Cat
{
//继承自Animal
Animal super;
//自身属性
int Age;
int Color;
}Cat;
//操作函数
void Cat_Constrator(Cat* const self, int Species,int Age,int Color); //构造函数
#endif
/****************************************************************
源文件:cat.c
****************************************************************/
#include "Cat.h"
//虚函数
static void Cat_Sound_(Animal const * const self);
void Cat_Constrator(Cat* const self, int Species,int Age,int Color)
{
//基类包含 vptr,子类会自动继承,但是,vptr 需要被子类的虚表重新赋值
//创建一个虚表,并指向虚函数
static struct Animal_VirtualTable const vtbl = { &Cat_Sound_ };
//初始化父类参数
Animal_Constrator(&self->super,Species);
self->super.Vptr = &vtbl; //初始化虚表指针
//初始化自身参数
self->Age = Age;
self->Color = Color;
}
static void Cat_Sound_(Animal const * const self)
{
Cat const * const self_ = (Cat const *)self;
printf("miao,I'm a cat.\n");
}
/****************************************************************
主文件:main.c
****************************************************************/
#include <stdio.h>
#include <Dog.h>
#include <Cat.h>
int main()
{
Dog d1;
Cat c1;
Dog_Constrator(&d1,0,3,135);
Cat_Constrator(&c1,1,1,220);
Animal_Sound(&d1.super);
Animal_Sound(&c1.super);
return 0;
}
执行结果: