• Crest的语法宏的魔术汇演


    上文完成了用纯C语言描述一个简单的对象结构的工作,因为要用例子表现,所以这次我们要来设计一下Crest的语法,也就是要看一下如果Crest最终能够成功完成的话,我们的编程代码会是一个什么样子。

    最理想的面向对象语法当然是仿造C#、java这样的结构了,但是因为C语言要用头文件,所以估计最终的样式还是类似于C++。首先我们还是制定一个目标的样式,然后再去用Crest仿造实现。目标是这样的[代码1]:

    class CString: CObject, IUnknown, IDispatch
    {
     int length;
     char * buffer;
     
     public virtual void Format(char * format)
     {
     DoFormat(format);
     }
     
     public void DoFormat(char * format)
     {
     if( OnFormat != null ) OnFormat(format);
     }
     
     public abstract void OnFormat(char * format);
    }

    要想用Crest实现上面的结构,有几个问题要注意:

    1. this指针。所有的对象成员定义和调用都隐含有一个this指针
    2. 命名规范,CString的Format和CDateTime的Format肯定不是同一个东西,但是C语言不支持override,所以要保证成员函数不重名。

    经过两天的断断续续工作,最终呈现结果如下[代码2]:

    DECLARE_CLASS(CString)
     EXTENDS(CObject, IMPLEMENT2(IUnknown,IDispatch))
     
     DECLARE_FIELD(CString, int, length)
     DECLARE_FIELD(CString, char *, buffer)
     
     DECLARE_VIRTUAL1(CString, void, Format, const char * format)
     DECLARE_ABSTRACT1(CString, void, OnFormat,const char * format)
     
     DECLARE_METHOD1(CString, void, DoFormat,const char * format)
     
     DECLARE_CONSTRUCTOR(CString)
     DECLARE_DESTRUCTOR(CString)
    END_DECLARE(CString);

    这个风格是不是觉得有些累赘?bigtall开始也觉得不满意,但是后来发现借助C语言的Macro魔法,这样的结构反而是最简单的,或者说,比较爽!

    在最终演化到这个样子的代码风格之前,我们可以手工来实现一个不用macro的版本,有对比才有真相啊!我们还是参考(代码1)部分,根据我们上文得到的经验,可以很轻松把代码给出来[代码3]:

     
    struct Class_CString; 
    typedef struct Class_CString CString;
    void CString_Format (CString *self, const char * format);
    void CString_OnFormat (CString *self, const char * format);
    void CString_DoFormat (CString *self, const char * format);
    void CString_constructor (CString *self);
    void CString_destructor (CString *self);
     
    struct Class_CString{
     int length;
     char * buffer;
     void (*Format) (CString *self, const char * format);
     void (*OnFormat) (CString *self, const char * format);
    };
     

    多了好多东西,写起来很麻烦,如果我们以后增加更多的特性的话,恐怕会成为噩梦。Crest要想让别人也去用,语法上面一定要让人觉得“合算”---增加一定的繁琐,但是得到的有用特性更多。为了实现(代码2)到(代码3)的转换,我们来看一下实际(代码2)的头文件定义:

     /* filename: macropure.h */
    #if defined(DECLARATION) || defined(DEFINITION)
     
    #include "CrestMacro.h"
     
    DECLARE_CLASS(CString)
     .../*此处省略*/
    END_DECLARE(CString);
     
    #else
     #define DECLARATION
     #include "macropure.h"
     #undef DECLARATION
     
     #define DEFINITION
     #include "macropure.h"
     #undef DEFINITION
    #endif
     
    这里bigtall使用了大量的宏定义,而且用了一个很少用的特性:自己包含自己。通过自身的包含,结合#if..#else..#endif,我们实现了不同阶段的DECLARE_CLASS有不同的定义。这样做的结果就是写一次繁琐的定义,通过宏的转换,实现了完整的class的定义代码。这里可惜的是,要是#include也支持宏扩展的话,头文件可以更简单。另外bigtall还做了一个用cpp32预处理再包含.i文件的版本,因为可移植性的问题,否掉了。
     
    以上讲的是.h头文件,对于.c文件,Crest的代码是这样的:
    #include <stdio>
    #include "macropure.h"
     
    IMPL_VIRTUAL1(CString, void, Format, const char * format)
    {
     REF_METHOD(CString, DoFormat)(self, format);
    }
     
    IMPL_ABSTRACT1(CString, void, OnFormat,const char * format)
    {
     puts(format);
    }
     
    IMPL_METHOD1(CString, void, DoFormat,const char * format)
    {
     if( self->OnFormat != 0 )
     self->OnFormat(self, format);
    }
     
    IMPL_CONSTRUCTOR(CString)
    {
     self->length = 3;
     self->buffer = "abc";
     self->Format = REF_METHOD(CString, Format);
     self->OnFormat = REF_METHOD(CString, OnFormat);
    }
     
    IMPL_DESTRUCTOR(CString)
    {
    }
     
    void main()
    {
     CString str, *pStr;
     
     CONSTRUCT(CString, &str);
     NEW(CString, pStr);
     
     str.Format(&str, "abcdefg\n");
     pStr->Format(pStr, "cdefghijk\n");
     
     DELETE(CString, pStr);
     DESTRUCT(CString, &str);
    }

    上一篇:Crest简单对象的设计 (to be continue)

  • 相关阅读:
    损失函数及其梯度
    激活函数及其梯度
    梯度下降简介
    误差计算
    输出方式
    全连接层
    测试(张量)- 实战
    数据加载
    高阶操作
    java网络基础知识的简述
  • 原文地址:https://www.cnblogs.com/BigTall/p/1614390.html
Copyright © 2020-2023  润新知