上文完成了用纯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实现上面的结构,有几个问题要注意:
- this指针。所有的对象成员定义和调用都隐含有一个this指针
- 命名规范,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
#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)