一、前言

面向对象编程(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语言--面向对象编程思想_虚表

实现流程

  • 定义一个接口类,在接口类中定义虚表、虚表指针、虚函数;
  • 定义一个实现类,在实现类构造函数中显示的初始化虚表(即将本类的虚函数赋值给虚表中的函数指针),如未显示初始化则会调用接口类中的虚函数,而不会调用实现类中的虚函数;
  • 根据功能需求编写实现类的虚函数;
  • 在接口类中定义一个统一的对外公共接口,供所有子类对象访问;

接口类(类似于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;
}

执行结果

C语言--面向对象编程思想_虚表_02