zoukankan      html  css  js  c++  java
  • C语言面对对象设计模式汇编

    面向对象发展到今天,已经出现了许许多多优秀的实践、方法和技术。很多的技术都能够有效的提高软件质量。IBM上的《面向对象软件开发和过程》系列文章对面对对象设计从如下层面进行了详细的介绍:代码是核心、 案例实战(上)、 案例实战(下)、 重用、优化代码的组织、 针对契约设计、 业务建模。

    虽然文章中的案例实战或代码示例都是以Java、C++等面对对象语言为主,但是辅以一定的方法和工具,C语言一样能做出优秀的面对对象设计,因为软件设计的基本理念原则是相通的。C语言面对对象设计的主要难点在于,对于抽象、继承、泛型(模板)等面对对象设计手段,在语法层次上缺少直接的支持。

    本文试图对如下四个主要的面对对象设计手段提供C语言的解决方案和示例。

    • 抽象数据类型
    • 对象继承(又叫实现继承)
    • 接口继承
    • 函数模板

    抽象数据类型

    抽象数据类型:方法A

    要点:
    a. 头文件只提供类型声明和接口声明
    b. 类型定义和接口实现在.c中完成
    c. 接口支持参数类型检查

    /* stach.h */
    #ifndef STACK_H
    #define STACK_H
    
    typedef struct stack *stack;
    
    extern stack new(void);
    extern void free(stack *stk);
    extern int empty(stack stk);
    extern void push(stack stk, void *x);
    extern void *pop(stack stk);

    抽象数据类型:方法B

    要点:
    a. 头文件只提供接口声明
    b. 定义一个 void * 指针类型全局变量,封装接口需要的所有和对象相关的信息
    c. 类型定义和接口实现在.c中完成
    d. 接口不支持参数类型检查

    /* set.h */
    #ifndef    H
    #define    H
    
    //Set, Object 本质是对象size的指针,用于new一个新对象
    extern const void * Set;
    extern const void * Object;
    
    extern void * new (const void * type, ...);
    extern void delete (void * item);
    extern void * add (void * set, const void * element);
    extern void * find (const void * set, const void * element);
    extern void * drop (void * set, const void * element);
    extern int contains (const void * set, const void * element);
    extern unsigned count (const void * set);
    
    
    #endif
    
    /* main.c */
    int main ()
    {	void * s = new(Set);
    	void * a = add(s, new(Object));
    	void * b = add(s, new(Object));
    	void * c = new(Object);
    
    	if (contains(s, a) && contains(s, b))
    		puts("ok");
    
    	if (contains(s, c))
    		puts("contains?");
    
    	if (differ(a, add(s, a)))
    		puts("differ?");
    
    	if (contains(s, drop(s, a)))
    		puts("drop?");
    
    	delete(drop(s, b));
    	delete(drop(s, c));
    
    	return 0;
    }
    

      

    对象继承

    对象继承:方法A

    要点:
    a. 纯虚基类以聚合(关联)方式继承,类型为const void *以便于信息隐藏
    b. 非纯虚基类以组合方式继承,类型为const struct superclass_name
    c. 所有基类必须作为派生类第一个成员
    d. 基类在派生类中以命名为'_'进行信息隐藏
    e. 纯虚基类在各个派生类中实例化
    f. 对外部不暴露具体数据类型

    extern const void * Circle;        /* new(Circle, x, y, rad) */
    extern const void * Point;        /* new(Point, x, y); */
    
    void * new (const void * class, ...);
    void delete (void * item);
    void draw (const void * self);
    void move (void * point, int dx, int dy);
    
     /* .c */
    struct Class {
        size_t size;
        void * (* ctor) (void * self, va_list * app);
        void * (* dtor) (void * self);
        void (* draw) (const void * self);
    };
    
    struct Point {
        const void * class;
        int x, y;
    };
    
    struct Circle {
        const struct Point _;
        int rad;
    };
    
    void move (void * _self, int dx, int dy)
    {    struct Point * self = _self;
    
        self -> x += dx, self -> y += dy;
    }
    
    void draw (const void * self)
    {    const struct Class * const * cp = self;
    
        assert(self && * cp && (* cp) -> draw);
        (* cp) -> draw(self);
    }
    

      

    对象继承:方法B

    要点:
    a. 基类作为派生类的一个字段,但不必作为派生类的第一个字段
    b. 通过 container_of 方法找到派生类的基类
    c. 对外不暴露派生类类型,但暴露基类类型
    d. 支持多重继承
    e. 多用于业务逻辑/流程在派生类模块中实现的场景,基类为派生类提供公共服务

    struct ep_device {
        struct usb_endpoint_descriptor *desc;
        struct usb_device *udev;
        struct device dev;
    };
    #define to_ep_device(_dev) 
        container_of(_dev, struct ep_device, dev)
    

      

    对象继承:方法C

    要点:
    a. 派生类作为基类的一个字段,此字段以void *类型定义
    b. 在派生类模块中对基类此字段进行初始化
    c. 对外不暴露派生类类型,但暴露基类类型
    d. 多用于业务逻辑/流程在基类模块中实现的场景,派生类为基类提供个性化服务

    struct super_block {
    /* omitted */
        void      *s_fs_info;        /* Filesystem private info */
    /* omitted */
    };
    
    int autofs_fill_super(struct super_block *s, void *data, int silent)
    {
        struct autofs_sb_info *sbi;
    /* omitted */
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (!sbi)
            goto fail_unlock;
    
        s->s_fs_info = sbi;
    /* omitted */
    }
    

      

    接口继承

    接口继承:虚函数表实现

    要点:
    a. 派生接口对象通过字段inherits继承基接口对象。
    b. 派生接口对象通过ata_finalize_port_ops初始化。
    c. C99中,若数据结构体中的某个字段被重复初始化,最后一次初始化有效。根据这个特点,实现接口成员的覆盖功能。

    struct  ata_port_operations {
        /* omitted */
        void (*sff_dev_select)(struct ata_port *ap, unsigned int device);
        /* omitted */
    
        /*
         * ->inherits must be the last field and all the preceding
         * fields must be pointers.
         */
        const struct ata_port_operations    *inherits;
    };
    
    const struct ata_port_operations ata_base_port_ops = {
        .prereset        = ata_std_prereset,
        .postreset        = ata_std_postreset,
        .error_handler        = ata_std_error_handler,
    };
    
    const struct ata_port_operations sata_port_ops = {
        .inherits        = &ata_base_port_ops,
        .qc_defer        = ata_std_qc_defer,
        .hardreset        = sata_std_hardreset,
    };
    const struct ata_port_operations sata_pmp_port_ops = {
        .inherits        = &sata_port_ops,
        .pmp_prereset        = ata_std_prereset,
        .pmp_hardreset    = sata_std_hardreset,
        .pmp_postreset    = ata_std_postreset,
        .error_handler        = sata_pmp_error_handler,
    };
    
    static void ata_finalize_port_ops(struct ata_port_operations *ops)
    {
        static DEFINE_SPINLOCK(lock);
        const struct ata_port_operations *cur;
        void **begin = (void **)ops;
        void **end = (void **)&ops->inherits;
        void **pp;
        if (!ops || !ops->inherits)
            return;
        spin_lock(&lock);
        for (cur = ops->inherits; cur; cur = cur->inherits) {
            void **inherit = (void **)cur;
            for (pp = begin; pp < end; pp++, inherit++)
            if (!*pp)
                *pp = *inherit;
        }
        for (pp = begin; pp < end; pp++)
            if (IS_ERR(*pp))
                *pp = NULL;
        ops->inherits = NULL;
    
        spin_unlock(&lock);
    }
    

    接口继承:宏实现

    要点:

    a. 基类接口对象用宏实现。
    b. 派生接口对象通过直接内嵌基类接口对象宏来实现继承。
    c. C99中,若数据结构体中的某个字段被重复初始化,最后一次初始化有效。根据这个特点,实现接口成员的覆盖功能。
    d. 只适用于两层继承结构。

    #define BCM_XXX_OPS   .dwBoardId = 0xffff, 
                          .trunk_id_translate = NULL, 
                          .trunk_add_port = bcm_XXX_trunk_add_port, 
    					  ... 
                          .trunk_del_port = bcm_XXX_trunk_del_port
    					  
    BCM_OPERATIONS bcm_XXX_table[]=
    {
        {BCM_XXX_OPS},    /*default*/
        {BCM_XXX_OPS,   .dwBoardId = _BT_3G_USRUD,
                        .pre_config = bcm_XXX_pre_config,
                        .packet_pro_config = bcm_XXX_packet_pro_config},
        {BCM_XXX_OPS,   .dwBoardId = _BT_3G_HMPUE,
                        .pre_config = bcm_XXX_pre_config,
                        .packet_pro_config = bcm_XXX_packet_pro_config},
        {_BT_3G_NULL,0},
    };					  
    

      

    函数模板

    函数模板: 参数多态实现

    要点:
    a. 通用操作,如:构造函数、解析函数、比较函数、复制函数等
    b. 函数模板参数以 void * 定义
    c. 把相关模板函数转化为纯虚基类的成员函数
    d. 模板函数基于纯虚基类上实现
    e. 每个派生类继承纯虚基类,纯虚基类以关联方式继承,类型为const void *以便于信息隐藏
    f. 所有基类必须作为派生类第一个成员,所以不支持多重继承方式
    g. 派生类具体实现自己特定接口

    /* new.h */
    void * new (const void * class, ...);
    void delete (void * item);
    
    void * clone (const void * self);
    int differ (const void * self, const void * b);
    
    size_t sizeOf (const void * self);
    
    /* new.r */
    struct Class {
        size_t size;
        void * (* ctor) (void * self, va_list * app);
        void * (* dtor) (void * self);
        void * (* clone) (const void * self);
        int (* differ) (const void * self, const void * b);
    };
    
    /* new.c */
    void * new (const void * _class, ...)
    {    const struct Class * class = _class;
        void * p = calloc(1, class -> size);
    
        assert(p);
        * (const struct Class **) p = class;
    
        if (class -> ctor)
        {    va_list ap;
    
            va_start(ap, _class);
            p = class -> ctor(p, & ap);
            va_end(ap);
        }
        return p;
    }
    
    /* string.h */
    extern const void * String;
    
    /* string.c */
    struct String {
        const void * class;    /* must be first */
        char * text;
    };
    
    static void * String_ctor (void * _self, va_list * app)
    {    struct String * self = _self;
        const char * text = va_arg(* app, const char *);
    
        self -> text = malloc(strlen(text) + 1);
        assert(self -> text);
        strcpy(self -> text, text);
        return self;
    }
    
    
    static const struct Class _String = {
        sizeof(struct String),
        String_ctor, String_dtor,
        String_clone, String_differ
    };
    
    const void * String = & _String;
    
    
    
    /* app.c */
    
    int main ()
    {    void * a = new(String, "a");
        //...
        delete(a);
        return 0;
    }
    

      

      

    函数模板: 宏实现

    要点:

    a. 函数定义成宏表达式,因为宏表达式不携带类型。当然这损失了代码可维护性。

    b. 函数参数类型通过C关键词typeof获取

    c. 变量读写尽量利用内存操作,因为内存操作可泛化具体数据类型,通过union和sizeof获取参数首址和长度。

    #define WRITE_ONCE(x, val) 
    ({                            
        union { typeof(x) __val; char __c[1]; } __u =    
            { .__val = (__force typeof(x)) (val) }; 
        __write_once_size(&(x), __u.__c, sizeof(x));    
        __u.__val;                    
    })
    
    
    static __always_inline void __write_once_size(volatile void *p, void *res, int size)
    {
        switch (size) {
        case 1: *(volatile __u8 *)p = *(__u8 *)res; break;
        case 2: *(volatile __u16 *)p = *(__u16 *)res; break;
        case 4: *(volatile __u32 *)p = *(__u32 *)res; break;
        case 8: *(volatile __u64 *)p = *(__u64 *)res; break;
        default:
            barrier();
            __builtin_memcpy((void *)p, (const void *)res, size);
            barrier();
        }
    }
    

      

    函数模板: 函数指针实现

    要点:

    a. 构造调用服务对象,来封装函数及其参数信息,不同的函数通过服务id来识别

    b. 通过可变参数实现不同服务的参数提取

    #include <stdio.h>
    #include <stdarg.h>
    
    struct call_svc {
        long id;
        long func;
        long arg_num;
    };
    
    static int a(void)
    {
        printf("%s(void)
    ", __FUNCTION__);
        return 0;
    }
    
    static int b(long arg1)
    {
        printf("%s(%ld)
    ", __FUNCTION__, arg1);
        return 0;
    }
    
    static int c(long arg1, long arg2, char* str)
    {
        printf("%s(%ld, %ld, %s)
    ", __FUNCTION__, arg1, arg2, str);
        return 0;
    }
    
    static struct call_svc svc[] = {
        {0, (long)&a, 0},
        {1, (long)&b, 1},
        {2, (long)&c, 3},
    };
    
    static int call(long id, ...)
    {
        int svc_num = sizeof(svc)/sizeof(svc[0]);
        int i ,ret;
        va_list argptr;
        
        for(i=0; i<svc_num; i++)
        {
            if(id == svc[i].id)
                break;
        }
        
        if(i >= svc_num)
        {
            printf("unsupported svc id: %ld
    ", id);
            return -1;
        }
    
        va_start(argptr, svc[i].arg_num); 
        
        switch (svc[i].arg_num) {
            case 0:
                ret = ((int (*)())svc[i].func)(); 
            break;
            
            case 1:
            {
                long v1 = va_arg( argptr, long);
                ret = ((int (*)(long))svc[i].func)(v1); 
            }
            break;
            
            case 3:
            {
                long v1 = va_arg( argptr, long);
                long v2 = va_arg( argptr, long);
                char *v3 = va_arg( argptr, char *);
                ret = ((int (*)(long, long, char *))svc[i].func)(v1, v2, v3); 
            }
    
            break;
            
            default:
            printf("unsupported svc param number. id: %ld, arg_num: %ld.
    ", id, svc[i].arg_num);
            break;
        }
        va_end(argptr);
        
        return ret;
    }
    
    
    int main(void)
    {
        call(0);
        call(1, 11);
        call(2, 11, 22, "hello world");
    
        return 0;
    }
    

      

      

  • 相关阅读:
    Jupyter 魔术命令(magic commands)
    Matplotlib中plt.rcParams用法(设置图像细节)
    Neural Networks and Deep Learning(week4)Building your Deep Neural Network: Step by Step
    C语言上机复习(一)文件操作
    Neural Networks and Deep Learning(week4)深层神经网络(Deep Neural Networks)
    maven pom.xml几个特殊的插件
    maven pom.xml中的 build说明
    pom.xml的继承、聚合与依赖
    eclipse自动补全设置
    maven insall跳过测试
  • 原文地址:https://www.cnblogs.com/wahaha02/p/6667981.html
Copyright © 2011-2022 走看看