• 用 C 语言实现面向对象编程


    一、类的封装实现:借用高焕堂的宏头文件,类很容易封装为如下的格式

    1、类的定义,其中 CLASS()  是 lw_oopc_kc.h 中定义的宏

    #include "lw_oopc_kc.h"

    CLASS(A)

    {

    int a; void(*init)(void*,int); void(*put)(void*);

    };

    2、成员函数的实现

    类的封装实质是用借用 struct  结构体,用函数指针来表示 C++中类的方法(成员函数)。接下来给类 的方法写实体函数。

    void init_A(void *t,int x)

    {

    A *cthis = (A*)t;

    cthis->a = x;

    }

    void put_A(void*t)

    {

    A *cthis = (A*)t;

    printf(" %d ",cthis->a);

    }

    3、类(结构体)中的函数指针与实现函数的关联 通过下面的宏把类的方法(函数指针)和实现函数关联:

    CTOR(A)

    FUNCTION_SETTING (init, init_A); FUNCTION_SETTING (put, put_A);

    END_CTOR

    4、对象的定义、构造和初始化

    如果没有这个连接处理,类(实际是 struct)中的函数指针就没有函数的功能。函数 init_A()是 XXX_A()  的命名模式,是指明 XXX_A()属于 类的函数,方便程序的理解和维护。下面就是要构造 类。在 C++中这个工作系统自动调用构造函数实现而在 C  中,这个过程智能显示调用来实现。借助 lw_oopc_kc.h (或"lw_oopc.h")可以利用宏CLASS_CTOR(classobj)来将定义的对象进行构造,使之 有数据的同时有方法的功能。实例化一个对象 步子如下:

    A   aa1;                           // 1、定义对象

    CLASS_CTOR(Aaa1);       // 2、构造对象使得函数指针和函数关联

    aa1.init(&aa110);               // 3、初始化对象的成员变量,注意要: &aa1(取地址)

    二、继承的实现:

    1、子类的定义:在类的开头借用已经定义的类进行定义一个变量,为了更加明白,表明是继承,增加一个宏定义:

    #define INHERIT(BASE)    IMPLEMENTS(BASE)

    于是以类 继承类 为例子如下:

    CLASS(B)

    {

    INHERIT(A);              //  继承 类 inb;                                   //  子类的成员 void (*init) (void*, int x);

    void (*put) (void*);

    };

    2、子类的成员函数实现,为了方便辨别,类 的成员函数带后缀 ‘_B

    void init_B (void*t, int x, int y)

    {

    *cthis =   (B*) t;

    CLASS_CTOR(A, cthis->A);               //----继承的基类在这里构造,对象是 cthis->A cthis->A.init(&cthis->A, x);                //----继承的基类的初始化注意:&cthis->A cthis->b = y;

    }

    void put_B (void *t)

    {

    *cthis = (B*) t;

    cthis->A.put (&cthis->A);                    //---子类调用父类的方式

    printf(" %d ",cthis->b);                          //---出类成员

    }

    3、子类的构造函数,和无继承类一样,将函数指针和函数关联

    CTOR(B)

    FUNCTION_SETTING (init, init_B);                    //---数指针和函数关联的宏

    FUNCTION_SETTING (put, put_B); END_CTOR

    说明:对基类的构造,不能在子类的构造宏 CTOR(B和 END_CTOR 之间进行,因为那时候子类 没有实例化,故没有实体对象,CLASS_CTOR(A, cthis->A);不能放在里面,只好放在 init_B() 函数里面,因为那时候 类已经有实例化对象了。这样的做法与 C++的做法不一样。C++在构造 的对象时,先调用 类的构造函数实例化对象中的基类部分。下面为main()函数的调用处理:

    inmain()

    {

    aa1; B b

    CLASS_CTOR(A,aa1);                              //--构造 aa对象 aa1.init(&aa1,5);                                                               //--初始化 aa对象aa1.put(&aa1);                                                               //--调用 aa对象的成员函数

    CLASS_CTOR(B, b);                                //---造 对象

    b.init(&b,100,78);                                     //--初始化 对象,包括基类 的构造和初始化

    b.put(&b);                                                //--调用 对象成员函数

    b.A.put(&b.A);                                         //--调用 对象的基类成员函数

    retur0;

    输出结果为5    100   78      100

    三、多态的实现:多态,简而言之即一个接口,多种实现。也就是用相同的抽象类的代码实现不同 的功能。在 中多态的实现是通过接口来实现的。借用 lw_oopc.h 宏文件,设计一个计算的多态例子如下:

    1接口的定义:本例是实现加法、减法运算。加和减都是调用类的同一个成员函数,却分别实现 了加、减的功能。本例的接口表示获得计算结果,但不知道采样什么样的计算方法。

    /*    operater.h   */

    #ifndef OPER_H

    #define OPER_H INTERFACE(IOPERATOR)

    {

    double (*GetResult)(double,double);

    };

    #endif

    /*-------------end of operater.h ------------------*/

    2、 在加法类 Add 中实现接口 IOPERATOR

    /*****   Add.C ***/

    #include "lw_oopc_kc.h"

    #include"operater.h"      // 头文件顺序很重要,lw_oopc_kc.h 在前,原因很简单不解释

    #include "classes.h"

    /************************** 类 Add 定义在 classes.h 

    CLASS(Add)

    {

    IMPLEMENTS(IOPERATOR);

    };************/

    static double GetResult(double a,double b)

    {

    return (a+b);

    }

    CTOR(Add)

    FUNCTION_SETTING(IOPERATOR.GetResult,GetResult); END_CTOR

    /***----- END OF ADD.C-----****/

    3、 在减法类 Sub 中实现接口 IOPERATOR

    /***--- Sub.c ---******/

    #include "lw_oopc_kc.h"

    #include"operater.h"

    #include "classes.h"

    /***********类 Sub 定义在 classes.h 

    CLASS(Sub)

    {

    IMPLEMENTS(IOPERATOR);

    };*/

    static double GetResult(double a,double b)

    {

    return (a-b);

    }

    CTOR(Sub) FUNCTION_SETTING(IOPERATOR.GetResult,GetResult);

    END_CTOR

    /***----- END OF Sub.C-----****/

    4


     

    4、 组合,把 operater.hAdd.CSub.C 和 main.C 组成一个工程,main.c 文件如下

    /***--- main.c ---******/

    #include<stdio.h>

    #include "lw_oopc_kc.h"

    #include"operater.h"      // 头文件顺序很讲究,lw_oopc_kc.h 必须在前

    #include "classes.h" int  main()

    {

    int a = 10, b=5;

    int c1,c2;

    IOPERATOR *poper;               //--定义接口指针,用指针实现多态

    Add A;                          //---对象 成员函数实现加法

    Sub S;                          //---象 成员函数实现减法

    CLASS_CTOR(Add, A); CLASS_CTOR(Sub, S);

    //---态内存处理方法

    poper = &A;        //也可以动态内存方法:oper New(Add); 记得 free()

    c1 = (poper->GetResult(a,b));      // c1 结果 15 ( a+b

    poper = &S;

    c2 = poper->GetResult(a,b);      // c2 结果a-b

    return 0;

    }

    /***----- END OF main.C-----****/

    总结:

    1、在 lw_oopc_kc.h 的基础上,为了增加可理解性,不改变原作含义为前提下,增加了以下宏

    #define CLASS_CTOR(Class,obj)       Class##Setting(&obj)        //--对象的构造宏

    #define INHERIT(BASE)     IMPLEMENTS(BASE)                        //---类继承宏

    #ifndef LW_OOPC_PURE_STATIC

    #ifndef LW_OOPC_STATIC

    #define New(Class)     Class##New()                  //--象动态构造宏

    #endif

    #endif

    2类的实例化必须有 3 步:定义、构造、初始化。尤其初始化时候通常是通过指针的应用来实现对类内部成员的访问。

    3继承实现方法:用父类名在子类中定义一个对象作为子类的一个成员变量,通过拥有该对象实 现子类对父类功能的拥有,即继承。

    注意:子类成员中用父类定义的对象,其构造函数要放在子类的初始化函数里(本人的解决方 法),因为子类的构造函数通过宏实现,不能直接调用父类的构造函数(如果您有更好办法,请和给大家分享)。

    5、 函数和函数指针的写法:将函数名变为指针,函数参数只要参数说明。

    e.g.        double GetResult(double a,double b) 转为函数指针为:

    double GetResult(double, double

    ------------------------------------------------------------------------------------

    附:lw_oopc_kc.h 宏文件内容

    /*  lw_oopc_kc.h */

    #ifndef _LW_OOPC_H

    #define _LW_OOPC_H

    #include <stdlib.h>

    #define CLASS(type)  typedef struct type type;  struct type

    #ifndef LW_OOPC_PURE_STATIC

    #ifndef LW_OOPC_STATIC

    #ifndef LW_OOPC_DYNAMIC

    #define CTOR(type) 

    void* type##Setting(type*);      

    void* type##New()

    {  

    struct type *t; 

    = (struct type *)malloc(sizeof(struct type)); 

    return type##Setting(t); 

    }  

    void* type##Setting(type *t) 

    {

    #else

    #define CTOR(type) 

    void* type##New()

    {  

    struct type *t; 

    = (struct type *)malloc(sizeof(struct type));

    #endif

    #else

    #define CTOR(type) 

    void* type##Setting(type *t) 

    {

    #endif

    #endif

    #define END_CTOR return (void*)t;      }

    #define FUNCTION_SETTING(f1, f2)      t->f1 = f2;

    #define IMPLEMENTS(type) type type

    #define INTERFACE(type)  typedef struct type type;  struct type

    #endif

    /*     end     */

  • 相关阅读:
    C# 随机生成姓名的方法
    Task 异步编程测试案例及基础应用说明
    C# 多线程 Parallel.For 和 For 谁的效率高?那么 Parallel.ForEach 和 ForEach 呢?
    C# SignalR 即时通信
    C#中out和ref之间的区别
    LInq之Take Skip TakeWhile SkipWhile Reverse Union Concat 用法
    C# LINQ 详解 From Where Select Group Into OrderBy Let Join
    JS 数组去重的几个方法
    attachEvent和addEventListener区别
    Event事件跨浏览器封装
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13318945.html
Copyright © 2020-2023  润新知