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)

posted on 2009-12-01 11:23  老翅寒暑  阅读(1679)  评论(1编辑  收藏  举报

导航