参照
C语言实现封装、继承和多态–通过创建一个VTable(virtual table)和在基类和派生类对象之间提供正确的访问
如何实现 C 语言的继承和多态–通过函数指针来实现的继承与多态,简单明了,animal基类,cat,dog两个派生类
技巧:用 C 语言实现程序的多态性–oid *:万能的指针“挂钩”
【C】——C利用回调函数实现多态
多态 (polymorphism
) 一词最初来源于希腊语polumorphos
,含义是具有多种形式或形态的情形。在程序设计领域,一个广泛认可的定义是“一种将不同的特殊行为和单个泛化记号相关联的能力”。
然而在人们的直观感觉中,多态的含义大约等同于“同一个方法对于不同类型的输入参数均能做出正确的处理过程,并给出人们所期望获得的结果”,也许这正体现了人们对于多态性所能达到的效果所寄予的期望:使程序能够做到越来越智能化,越来越易于使用,越来越能够使设计者透过形形色色的表象看到代码所要触及到的问题本质。
作为读者的你或许对于面向对象编程已有着精深的见解,或许对于多态的方便与神奇你也有了深入的认识。这时候你讶异的开始质疑了:“多态,那是面向对象编程才有的技术,C 语言是面向过程的啊!”而我想说的是,C 语言作为一种编程语言,也许并不是为了面向对象编程而设计,但这并不意味着它不能实现面向对象编程所能实现的功能,就比如说,多态性。
C语言能够模拟实现面向对象语言具有的特性,包括:多态,继承,封装等,现在很多开源软件都了用C语言实现了这几个特性,包括大型开源数据库系统postgreSQL
,可移植的C语言面向对象框架GObject
,无线二进制运行环境BREW
。采用C语言实现多态,继承,封装,能够让软件有更好的可读性,可扩展性。另外,在 Linux 内核里面也大量使用了面向对象的思想,比如虚拟文件系统,设备驱动等模。
在C语言中,可以用结构+函数指针来模拟类的实现,而用这种结构定义的变量就是对象。
封装的主要含义是隐藏内部的行为和信息,使用者只用看到对外提供的接口和公开的信息。
有两种方法实现封装:
利用C语言语法。在头文件中声明,在C文件中真正定义它
这样可以隐藏内部信息,因为外部不知道对象所占内存的大小,所以不能静态的创建该类的对象,只能调用类提供的创建函数才能创建。这种方法的缺陷是不支持继承,因为子类中得不到任何关于父类的信息。
把私有数据信息放在一个不透明的priv变量或者结构体中。只有类的实现代码才知道priv或者结构体的真正定义。
这样可以隐藏内部信息,因为外部不知道对象所占内存的大小,所以不能静态的创建该类的对象,只能调用类提供的创建函数才能创建。这种方法的缺陷是不支持继承,因为子类中得不到任何关于父类的信息。
头文件:point.h
//头文件:point.h
#ifndef POINT_H
#define POINT_H
struct Point;
typedef struct Point point;
point * new_point(); //newer a point object
void free_point(point *point_);// free the allocated space
#endif
C文件:point.c
//C文件:point.c
#include”point.h”
strcut Point
{
int x;
int y;
};
point * new_point()
{
point * new_point_ = (point *) malloc(sizeof(point));
return new_point_;
}
void free_point(point *point_)
{
if(point_ == NULL)
{
return;
}
free(point_);
}
把私有数据信息放在一个不透明的priv
变量或者结构体中。只有类的实现代码才知道priv或者结构体的真正定义。
头文件:point.h
#ifndef POINT _H
#define POINT_H
typedef struct Point point;
typedef struct pointPrivate pointPrivate;
strcut Point
{
Struct pointPrivate *pp;
};
int get_x(point *point_);
int get_y(point *point_);
point * new_point(); //newer a point object
void free_point(point *point_);// free the allocated space
#endif
C文件:point.c
//C文件:point.c
#include”point.h”
struct pointPrivate
{
int x;
int y;
}
int get_x(point *point_)
{
return point_->pp->x;
}
int get_y(point *point_)
{
return point_->pp->y;
}
内存管理类new.h
//内存管理类new.h
#ifndef NEW_H
#define NEW_H
void * new (const void * class, ...);
void delete (void * item);
void draw (const void * self);
#endif
内存管理类的C文件:new.c
//内存管理类的C文件:new.c
#include "new.h"
#include "base.h"
void * new (const void * _base, ...)
{
const struct Base * base = _base;
void * p = calloc(1, base->size);
assert(p);
*(const struct Base **) p = base;
if (base ->ctor)
{
va_list ap;
va_start(ap, _base);
p = base ->ctor(p, &ap);
va_end(ap);
}
return p;
}
void delete (void * self)
{
const struct Base ** cp = self;
if (self && * cp && (* cp) —> dtor)
{
self = (* cp) —>dtor(self);
}
free(self);
}
void draw (const void * self)
{
const struct Base * const * cp = self;
assert(self &&* cp && (* cp)->draw);
(* cp) ->draw(self);
}
基类:base.h
//基类:base.h
#ifndef BASE_H
#define BASE_H
struct Base
{
size_t size; //类所占空间
void * (* ctor) (void * self, va_list * app); //构造函数
void * (* dtor) (void * self); //析构函数
void (* draw) (const void * self); //作图
};
#endif
内存管理类的C文件:new.c
//内存管理类的C文件:new.c
#include "new.h"
#include "base.h"
void * new (const void * _base, ...)
{
const struct Base * base = _base;
void * p = calloc(1, base->size);
assert(p);
* (const struct Base **) p = base;
if (base ->ctor)
{
va_list ap;
va_start(ap, _base);
p = base ->ctor(p, &ap);
va_end(ap);
}
return p;
}
void delete (void * self)
{
const struct Base ** cp = self;
if (self && * cp && (* cp) —> dtor)
{
self = (* cp) —>dtor(self);
}
free(self);
}
void draw (const void * self)
{
const struct Base * const * cp = self;
assert(self &&* cp && (* cp)->draw);
(* cp) ->draw(self);
}
Point头文件(对外提供的接口):point.h
//Point头文件(对外提供的接口):point.h
#ifndef POINT_H
#define POINT_H
extern const void * Point; /* 使用方法:new (Point, x, y); */
#endif
Point内部头文件(外面看不到):point.r
#ifndef POINT_R
#define POINT_R
struct Point
{
const void * base; //继承,基类指针,放在第一个位置,const是防止修改
int x, y; //坐标
};
#endif
Point的C文件:point.c
//Point的C文件:point.c
#include "point.h"
#include "new.h"
#include "point.h"
#include "point.r"
static void * Point_ctor (void * _self, va_list * app)
{
struct Point * self = _self;
self->x = va_arg(*app, int);
self->y = va_arg(*app, int);
return self;
}
static void Point_draw (const void * _self)
{
const struct Point * self = _self;
printf("draw (%d,%d)", self -> x, self -> y);
}
static const struct Base _Point =
{
sizeof(struct Point), Point_ctor, 0, Point_draw
};
const void * Point = &_Point;
Circle头文件(对外提供的接口):circle.h
//Circle头文件(对外提供的接口):circle.h
#ifndef CIRCLE_H
#define CIRCLE_H
extern const void *Circle; /* 使用方法:new (Point, x, y); */
#endif
Circle内部头文件(外面看不到):circle.r
//Circle内部头文件(外面看不到):circle.r
#ifndef CIRCLE_R
#define CIRCLE_R
struct Circle
{
const struct Point point; //放在第一位,可表继承
int radius;
};
#endif
Cricle的C文件:Cricle.c
//Cricle的C文件:Cricle.c
#include "new.h"
#include "point.h"
#include "point.r"
#include "circle.h"
#include "circle.r"
static void * Cricle_ctor (void * _self, va_list * app)
{
struct Cricle * self = _self;
self->x = va_arg(*app, int);
self->y = va_arg(*app, int);
return self;
}
static void Cricle_draw (const void *_self)
{
const struct Cricle * self = _self;
printf("draw (%d,%d), radius = %d", self->x, self->y, self->radius);
}
static const struct Base _Cricle =
{
sizeof(struct Cricle), Cricle_ctor, 0, Cricle_draw
};
const void * Cricle = &_Cricle;
//测试程序:main.c
#include "point.h"
#include "new.h"
int main (int argc, char ** argv)
{
void * p = new(Point, 1, 2);
draw(p);
delete(p);
}