最近有点无事可干,遇见瓶颈期了,就给自己找点事情,不浪费时间就是了。学习了gobject,就对这个用C来模拟面向对象编程的方法有点着迷。我的模拟,只能实现单继承,每一个结构体中含有了myobject中虚函数表指针。MyObject中的vtable是为了调用子类的dispose函数进行资源释放。
my_object.h
#ifndef MY_OBJECT_H_
#define MY_OBJECT_H_
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#define MY_OBJECT(obj) ((MyObject*)obj)
#define MY_OBJECT_CLASS(kclass) ((MyObjectClass*)kclass)
#define MY_OBJECT_VTABLE(obj) (MY_OBJECT(obj)->vtable)
#define atomic_cas(dst, old, new) __sync_bool_compare_and_swap((dst), (old), (new))
#define atomic_lock(ptr)\
while(!atomic_cas(ptr,0,1))
#define atomic_unlock(ptr)\
while(!atomic_cas(ptr,1,0))
typedef struct _MyObject MyObject;
typedef struct _MyObjectClass MyObjectClass;
struct _MyObject{
MyObjectClass *vtable;//quite tricky
int lock;
int count;
};
struct _MyObjectClass{
void (*dispose)(MyObject*obj);
};
void *my_object_create(int size);
void *my_object_ref(MyObject *obj);
void my_object_unref(MyObject *obj);
MyObjectClass *my_object_vtable();
#endif /* MY_OBJECT_H_ */
my_object.c
my_object_free函数中调用子类的dispose函数,这个函数可以认为被子类重载。
#include "my_object.h"
void my_object_dispose(MyObject *obj);
MyObjectClass vtable={
.dispose=my_object_dispose,
};
void my_object_free(MyObject *obj){
obj->vtable->dispose(obj);
free(obj);
}
void *my_object_create(int size){
MyObject *ins=NULL;
ins=(MyObject*)malloc(size);
memset(ins,0,size);
if(ins){
ins->lock=0;
ins->count=1;
}
return ins;
}
void *my_object_ref(MyObject *obj){
MyObject *ins=NULL;
atomic_lock(&obj->lock);
if(obj->count){
obj->count++;
ins=obj;
}
atomic_unlock(&obj->lock);
return ins;
}
void my_object_unref(MyObject *obj){
atomic_lock(&obj->lock);
if(obj->count){
obj->count--;
}
atomic_unlock(&obj->lock);
if(obj->count==0){
my_object_free(obj);
}
}
MyObjectClass * my_object_vtable(){
return &vtable;
}
void my_object_dispose(MyObject *obj){
printf("%s\n",__FUNCTION__);
}
子类: my_dispatcher.h
#ifndef MY_DISPATCHER_H_
#define MY_DISPATCHER_H_
#include "my_object.h"
typedef struct _MyDispatcher MyDispatcher;
typedef struct _MyDispatcherClass MyDispatcherClass;
#define MY_DISPATCHER(obj) ((MyDispatcher*)obj)
#define MY_DISPATCHER_CLASS(kclass)((MyDispatcherClass*)kclass)
//#define my_dispatcher_call(obj,method) (((MyDispatcherClass*)MY_OBJECT_VTABLE(obj))->method)
#define my_dispatcher_call(obj,method,...) do{\
MyDispatcherClass *vtable=(MyDispatcherClass*)MY_OBJECT_VTABLE(obj);\
vtable->method(__VA_ARGS__);\
}while(0)
typedef int SOCKET;
struct _MyDispatcher{
MyObject parent;
SOCKET fd;
void* poll_plugin;
int request_event;
uint8_t *buf;
int buf_len;
};
struct _MyDispatcherClass{
MyObjectClass parent_class;
void (*read_event)(MyDispatcher *self);
void (*write_event)(MyDispatcher *self);
int (*write)(MyDispatcher *self,void *data,int len);
};
MyDispatcher* my_dispatcher_new();
void my_dispatcher_free(MyDispatcher* obj);
MyDispatcherClass* my_dispatcher_vtable();
#endif /* MY_DISPATCHER_H_ */
my_dispatcher.c
#include "my_dispatcher.h"
MyDispatcherClass my_dispatcher_default_vtable;
static bool class_inited=false;
void my_dispatcher_class_init();
void my_dispacther_read_event(MyDispatcher *self){
printf("%s\n",__FUNCTION__);
}
void my_dispacther_write_event(MyDispatcher *self){
printf("%s\n",__FUNCTION__);
}
int my_dispacther_write(MyDispatcher *self,void *data,int len){
printf("%s\n",__FUNCTION__);
return 0;
}
MyDispatcher* my_dispatcher_new(){
MyDispatcher *ins;
ins=(MyDispatcher*)my_object_create(sizeof(MyDispatcher));
MY_OBJECT_VTABLE(ins)=my_dispatcher_vtable();
return ins;
}
void my_dispatcher_dispose(MyDispatcher* obj){
//resource allocation, free ptr in MyDispatcher;
if(obj->buf){
printf("free buffe len %d\n",obj->buf_len);
free(obj->buf);
obj->buf=NULL;
}
printf("%s\n",__FUNCTION__);
MyObjectClass *parent_class=my_object_vtable();
MY_OBJECT_CLASS(parent_class)->dispose(MY_OBJECT(obj));
}
void my_dispatcher_free(MyDispatcher* obj){
my_object_unref(MY_OBJECT(obj));
}
MyDispatcherClass* my_dispatcher_vtable(){
if(!class_inited){
my_dispatcher_class_init();
}
return &my_dispatcher_default_vtable;
}
void my_dispatcher_class_init(){
class_inited=true;
MyDispatcherClass *kclass=&my_dispatcher_default_vtable;
MyObjectClass *parent=my_object_vtable();
memcpy(kclass,parent,sizeof(*parent));
kclass->read_event=my_dispacther_read_event;
kclass->write=my_dispacther_write;
kclass->write_event=my_dispacther_write_event;
MY_OBJECT_CLASS(kclass)->dispose=my_dispatcher_dispose;
}
MY_OBJECT_CLASS(kclass)->dispose=my_dispatcher_dispose; 在创造新的类的时候,必须实现dispose函数,在这个函数中进行结构体内的指针资源的释放。不能释放结构体本身。结构体的释放有my_object_free(MY_OBJECT(obj))完成。
孙辈:
my_dispatcher_child.h
#ifndef MY_DISPATCHER_CHILD_H_
#define MY_DISPATCHER_CHILD_H_
#include "my_dispatcher.h"
typedef struct _MyDispatcherChild MyDispatcherChild;
typedef struct _MyDispatcherChildClass MyDispatcherChildClass;
#define MY_DISPATCHER_CHILD(obj) ((MyDispatcherChild*)obj)
#define MY_DISPATCHER_CHILD_CLASS(kclass)((MyDispatcherChildClass*)kclass)
//#define my_dispatcher_child_call(obj,method) (((MyDispatcherChildClass*)MY_OBJECT_VTABLE(obj))->method)
#define my_dispather_child_call(obj,method,...) do{\
MyDispatcherChildClass *vtable=(MyDispatcherChildClass*)MY_OBJECT_VTABLE(obj);\
vtable->method(__VA_ARGS__);\
}while(0)
struct _MyDispatcherChild{
MyDispatcher parent;
int a;
};
struct _MyDispatcherChildClass{
MyDispatcherClass parent_class;
void (*fun1)(void);
void (*fun2)(void);
};
MyDispatcherChild* my_dispacher_child_new();
void my_dispatcher_child_free(MyDispatcherChild* obj);
MyDispatcherChildClass* my_dispatcher_child_vtable();
#endif /* MY_DISPATCHER_CHILD_H_ */
my_dispatcher_child.c
#include "my_dispatcher_child.h"
MyDispatcherChildClass my_dispatcherchild_default_vtable;
static bool class_inited=false;
void my_dispatcher_child_class_init(void);
void my_fun1(void){
printf("%s\n",__FUNCTION__);
}
void my_fun2(void){
printf("%s\n",__FUNCTION__);
}
void my_child_read_event(MyDispatcherChild *self){
printf("%s\n",__FUNCTION__);
}
MyDispatcherChild* my_dispatcher_child_new(){
MyDispatcherChild *ins;
ins=(MyDispatcherChild *)my_object_create(sizeof(MyDispatcherChild));
MY_OBJECT_VTABLE(ins)=my_dispatcher_child_vtable();
return ins;
}
void my_dispatcher_child_dispose(MyDispatcherChild* obj){
//resource allocation, from ptr in MyDispatcher;
printf("%s\n",__FUNCTION__);
MyDispatcherClass *parent_class=my_dispatcher_vtable();
MY_OBJECT_CLASS(parent_class)->dispose(MY_OBJECT(obj));
}
void my_dispather_child_free(MyDispatcherChild* obj){
my_object_unref(MY_OBJECT(obj));
}
MyDispatcherChildClass* my_dispatcher_child_vtable(){
if(!class_inited){
my_dispatcher_child_class_init();
}
return &my_dispatcherchild_default_vtable;
}
void my_dispatcher_child_class_init(void){
class_inited=true;
MyDispatcherChildClass *kclass=&my_dispatcherchild_default_vtable;
MyDispatcherClass *parent=my_dispatcher_vtable();
memcpy(kclass,parent,sizeof(*parent));
kclass->parent_class.read_event=my_child_read_event; //override
kclass->fun1=my_fun1;
kclass->fun2=my_fun2;
MY_OBJECT_CLASS(kclass)->dispose=my_dispatcher_child_dispose;
}
main-test.c
#include <stdio.h>
#include <stdint.h>
#include "my_dispatcher.h"
#include "my_dispatcher_child.h"
int main(){
MyDispatcherChild *child=my_dispatcher_child_new();
my_dispatcher_call(child,read_event,child);
my_dispatcher_child_call(child,fun1);
MY_DISPATCHER(child)->buf=malloc(8*sizeof(uint8_t));
MY_DISPATCHER(child)->buf_len=8;
printf("%p\n",child->parent.parent.vtable);
printf("%p\n",my_dispatcher_child_vtable());
my_dispather_child_free(child);
return 0;
}
编译,使用cmake: cmake . 注意后面的点。
CMakeLists.txt
PROJECT(project)
cmake_minimum_required(VERSION 2.6)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -O2")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -O2")
SET(CMAKE_BUILD_TYPE "Debug")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -O2")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -O2")
set(CMAKE_CXX_FLAGS "-fPIC")
set(CMAKE_C_FLAGS "-fPIC")
add_definitions(-D__STDC_FORMAT_MACROS)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include_directories(${CMAKE_SOURCE_DIR}/)
set(object_FILES
my_object.c
my_dispatcher.c
my_dispatcher_child.c
)
add_library(object STATIC ${object_FILES})
set(EXECUTABLE_NAME "main")
add_executable(${EXECUTABLE_NAME} main-test.c)
target_link_libraries(${EXECUTABLE_NAME} object)
执行结果:
my_child_read_event
my_fun1
my_fun2
0x6020a0
0x6020a0
my_dispatcher_child_dispose
free buffe len 8
my_dispatcher_dispose
my_object_dispose
Just for fun.