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實現上面的結構,有幾個問題要注意:
- 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 <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)

公眾號:老翅寒暑
浙公網安備 33010602011771號