C 語言物件導向編程 理論加實踐 代碼

來源:互聯網
上載者:User

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 專欄,轉載請著名出處,謝謝!


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.