1.對象定義:
對象的定義包含對象的主要函數,大小,以及引用計數。
必須的函數包括 建構函式,解構函式,比較函數
對象的建立包含兩個過程:1). 在堆上分配動態記憶體。這就是為什麼必須填寫對象大小的原因 ,對象分配記憶體後,對象的所有成員會被初始化成0,
2).接下來就調用建構函式初始化對象的成員屬性。
2. 對象的析構
對象的析構包含兩個過程,1)釋放對象的成員,對象的解構函式負責此任務,2)釋放對象本身。
3.建構函式
建構函式只負責初始化而不會申請對象記憶體,對象傳給建構函式前已經分配記憶體。
4.解構函式
解構函式會釋放對象的成員,不會釋放對象本身,解構函式必須返回對象本身,以便於調用者可以釋放對象。
5.引用計數
引用計數用來作記憶體回收,一個定義良好的對象應該包含一個引用計數,用於指示有多少個指向實際對象的引用。
當一個對象被建立時,引用計數初始化為1.當你手動調用ref 及unref此值自動加1減1,當引用計數為0時對象被毀收。
6.繼承
我們知道,C語言不支援繼承,但是,任何C語言結構本身能夠強制指向其第一個元素的指標,這樣就可以達到繼承的目的。
理論的東西網上一大片,我就不扯了,直接上代碼:
spd_obj.h 源碼:
#ifndef SPD_OBJECT_H
#define SPD_OBJECT_H
#include <stdarg.h>
#include <stdio.h>
#ifdef __cplusplus extern "C" {
typedef void spd_obj_t;
typedef struct {
// ! The size of the object
size_t size;
spd_obj_t* (*constructor) (spd_obj_t *, va_list *);
spd_obj_t* (*destructor) (spd_obj_t *);
int (*comparator) (const spd_obj_t *, const spd_obj_t *);
} spd_obj_def_t;
/* release obj */
#define SPD_OBJ_SAFE_FREE(obj) if(obj) spd_obj_unref(obj),obj = NULL;
/* base class as is */
#define SPD_OBJ_DECLARE \
const void* __base__; \
size_t refCount;
/* get the definition of the object */
#define SPD_OBJ_DEF(obj) (const (spd_obj_def_t *)obj)
spd_obj_t *spd_obj_new(const spd_obj_def_t *, ...);
size_t *spd_obj_sizeof(const spd_obj_def_t *, ...);
spd_obj_t *spd_obj_ref(spd_obj_t *);
spd_obj_t *spd_obj_unref(spd_obj_t *);
void spd_obj_delete(spd_obj_t *);
spd_obj_t *spd_obj_cmp(const spd_obj_def_t *, const spd_obj_def_t *);
size_t *spd_obj_get_refcount(spd_obj_t *);
}
#endif
spd_obj.c 源碼:
#include "spd_obj.h"
typedef struct {
const void *base;
int refCount;
} spd_obj_header_t;
#define SPD_OBJ_HEADER_DEF(obj) (const (spd_obj_header_t*))
spd_obj_t *spd_obj_new(const spd_obj_def_t *obj,...)
{
spd_obj_t *newobj = spd_calloc(1, obj->size);
if(newobj) {
(*(const spd_obj_def_t **) newobj) = obj;
SPD_OBJ_HEADER_DEF(obj)->refCount = 1;
if(obj->constructor) {
va_list ap;
va_start(ap, obj);
newobj = obj->constructor(&newobj, &ap);
va_end(ap);
} else {
spd_log(LOG_WARNING, "must set constructor\n");
}
} else {
spd_log(LOG_ERROR, "failed to alloc\n");
}
return newobj;
}
size_t spd_obj_sizeof(const spd_obj_t *obj)
{
const spd_obj_def_t **objdef = (const spd_obj_def_t **)obj;
if(objdef && *objdef) {
return (*objdef->size;
} else {
spd_log(LOG_ERROR, "NULL OBJ\n");
return 0;
}
}
int spd_obj_cmp(const spd_obj_t *obj1, const spd_obj_t *obj2)
{
const spd_obj_def_t **objdef = (const spd_obj_def_t**)obj2;
if(objdef && *objdef && objdef->comparator) {
return objdef->comparator(obj1, obj2);
}
return -1;
}
spd_obj_t *spd_obj_ref(spd_obj_t *obj)
{
spd_obj_def_t *objhdr = SPD_OBJ_HEADER_DEF(obj);
if(objhdr && objhdr->refCount) {
objhdr->refCount++;
return obj;
}
return NULL;
}
spd_obj_t *spd_obj_unref(spd_obj_t *obj)
{
if(obj) {
spd_obj_header_t *objhdr = SPD_OBJ_HEADER_DEF(obj);
if(objhdr->refCount) {
if(!--objhdr->refCount) {
spd_obj_delete(obj);
return NULL;
}
} else {
return NULL;
}
}
return obj;
}
size_t spd_obj_get_refcount(spd_obj_t *obj)
{
return obj ? SPD_OBJ_HEADER_DEF(obj)->refCount : 0;
}
void spd_obj_delete(spd_obj_t *obj)
{
const spd_obj_def_t **objdef = obj;
if(obj && *obj) {
if((*obj)->destructor) { /* destructor only delete member*/
obj = (objdef)->destructor(obj);
} else {
spd_log(LOG_ERROR, "No destructor found\n");
}
free(obj); /* release obj itself */
}
}
測試代碼:
test_obj.c
#include "spd_obj.h"
typedef struct {
SPD_OBJ_DECLARE; /*base class , this is must */
const *name;
struct animal_t *pig;
} animal_t;
/* dog is a type of animal*/
typedef struct {
struct animal_t* animal; /* super class */
char *type;
} dog_t;
/*constructor */
static spd_obj_t* animal_create(spd_obj_t *obj, va_list *app)
{
animal_t *ani = obj;
if(ani) {
ani->name = spd_strdup(va_arg(*app, const char *);
}
return obj;
}
/* destructor */
static spd_obj_t* animal_destroy(spd_obj_t *obj)
{
animal_t *ani = obj;
if(ani) {
spd_free(ani->name);
spd_obj_unref(ani->pig);
}
return obj;
}
static spd_obj_t* animal_cmp(spd_obj_t *obj1, spd_obj_t*obj2)
{
const animal_t *p1 = obj1;
const animal_t *p2 = obj2;
int ret;
if((ret = strcasecmp(p1->name, p2->name))) {
return ret;
}
/* they are all pig ? */
if((ret = spd_obj_cmp(p1->pig, p2->pig))) {
return ret;
}
return 0; /* same */
}
static const spd_obj_def_t animal_def_t = {
sizeof(animal_t),
animal_create,
animal_destroy,
animal_cmp
};
/* the single interface you see */
#define ANIMAL_CREATE(name) spd_obj_new(&animal_def_t, (const char *)name)
static void test_animal()
{
animal_t *candy = ANIMAL_CREATE("Candy");
candy->pig = ANIMAL_CREATE("Sony");
SPD_OBJ_SAFE_FREE(candy);
}
int main(int argc ,char *argv[])
{
test_animal();
return 0;
}
本文來自 csdn lidp 專欄,轉載請著名出處,謝謝!