OOC-GCC 简介
OOC-GCC 概述
下载地址
http://code.google.com/p/ooc-gcc/downloads/list
其实这还是我对用C语言进行OO方式编程的一些尝试,最早的时候我在SF建了一个叫JCOOP的项目,后来搬到GOOGLE CODE
不过随着不断的改进,也对OO有了进一步的理解,
在这里先谈一下现在我对OO的理解,
所谓OO,本质是对象驱动型编程模式,其核心在于抽象,并将代码封装使之更易于复用.
所以说你用结构体来抽象描述某种事物并不意味着你的代码就不是OO的,所以说用C也是可以写出OO的代码的.
有人或许会更仔细的区分OO和OB,认为只有支持了多态,RTTI这些儿玩意儿的才是OO,其它的只能是OB
[※O→oriented,B→based]
我不想去争论这些没有太大意义的概念,因为C语言本身不是OO的语言.
不过话说回来,计算机的执行过程在逻辑上都本质是过程化的,因为汇编是过程的,机器码也是过程的.
而那些OO的语言只不过是编译器帮助完成了一些迷惑性的工作,帮你完成了内存分布,访问控制等的跑龙套的活而已.
无论何种类型的语言,执行过程都会遵循一定的顺序,所以说像C这类语言骨子里并不输给CPP,JAVA,
反倒是一些很高级的语言,引入了过多的语法糖,深入学习后总会感到有些瑕疵.
下面言归正传,
用C去模拟OO[这里说的OO包括OB和OO,是指一种思想,从对象入手的编程方式],首先要模拟的就是其最核心的东西.
虽然Ruby,CPP的技巧繁多,但依我现在来看,OO最重要的东西不是多态这些,而是如何去设计一个类,以及如何区别其他类.
本质上来说就是类的结构设计,类的构造与析构,如何调用类的成员.
对于用C模拟OO来说,类结构自然就是struct,普通成员依旧是普通成员,方法就是函数指针.至于虚函数与否,就是指向的问题了.
在目前的OOC-GCC中,通过宏class...eclass来定义一个类,通过ctor...ector和dtor...edtor宏来完成构造和析构.
而调用的时候则要用到new...del宏以及ini...fin宏,如果类在堆上,使用new...del,如果类在栈上,使用ini...fin.
至于继承的问题,用struct当然是struct中套struct了,而类型系统以及类型的转换,额外动手写是必须的,不过一种比较好的思路是
用union来包含不同的类型,并以一个变量来区分不同的类型,目前还没有弄这一块,因为个人觉得这样做太冗杂了.
OO本来就是简化编程的,弄得复杂了就不好了.
在最近的尝试中,还试着来模拟foreach这样的行为,但是目前的实现需要他typeof这种类别的关键字的支持[或者__typeof__类似的]
下面举一个Iterator的例子,当然这个Iterator和别的语言的必须是有所不同的.
假定我们要构造一个描述集合的类B,一个描述元素的类N.
要使用我这里的Iterator,只需让B包含一个IterationBase[或用typedef后的IBase],让N包含一个IterationNode[INode]
具体的类,以及构造与析构如下
//类声明
class(B) IBase ibase; eclass
//构造
ctor(B) ini0(IterationBase,&this->ibase); ector
//析构
dtor(B) emptyzs edtor
//////////////////
//类声明
class(N) INode inode; //这里v用来保存实际测试用的数据 int v; eclass
//构造
ctor(N) ini0(IterationNode,&(this->inode)); this->v=(int)param; ector
析构
dtor(N) emptyzs edtor
下面给出测试用的main函数
int main (int argc, char *argv[]) { //声明部分 Iterator itor; ini0(Iterator,&itor); N *n1=NULL,*n2=NULL,*n3=NULL,*n4=NULL; n1=new(N,(void *)111); n2=new(N,(void *)112); n3=new(N,(void *)113); n4=new(N,(void *)114); B *b; b=new0(B); //插入 // //将n1..n4绑定到b, //注意append前两个是不需要next的 // //第一次插入无论用append或prepend //都会使base中的指针指向插入的node itor.append(&b->ibase,&n1->inode); //以后每次的append或prepend都是针对 //当前base中的cur指针的 itor.append(&b->ibase,&n2->inode); //这里想要在整个base的尾部插入 //所以后面的每次插入都需要next一下 itor.next(&b->ibase); itor.append(&b->ibase,&n3->inode); itor.next(&b->ibase); itor.append(&b->ibase,&n4->inode); // //foreach遍历 N *np=NULL; //哈哈 foreach 遍历 ! foreach(np,b) printf("--%d",np->v); eforeach printf("\n"); //反着再遍历一遍 ! foreach_rev(np,b) printf("--%d",np->v); eforeach // //释放堆内存 del0(N,&n1); del0(N,&n2); del0(N,&n3); del0(N,&n4); del0(B,&b); return(0); }
正确的输出是
--111--112--113--114 --114--113--112--111
[※最后注明一下,OOC-GCC从名字上就能看出是针对GCC的,用C++的编译器肯定无法编译的
如果是其他纯C的编译器[最好支持C99扩展的],可能需要稍微修改一些,但量不会很大]
Wed, 26 Jan 2011 13:56:40 -1100
貌似不错呢,如果GObject引入了你这个东东,不知道会有什么新改观!
Wed, 26 Jan 2011 13:57:41 -1100
@纵横天下: 只是。。。代码包竟然是RAR格式……
Fri, 28 Jan 2011 05:06:50 -1100
@纵横天下:
我一直不是真正的*nix控,
我这个东西是在win下写的,所以用RAR很正常吧...
不过只要是gcc应该都可以编译的,因为我没有用win下专用的api,也不喜欢用...
如果从大小上说貌似lzma算法的小点,不过google空间够大了[就我这点宏而言]
如果是Linux下现在都有解压的工具啊,也是一键解压的吧,好像需要装个rar的扩展
[别说你习惯shell命令行,那东西会逼我撞墙....
不是不用,实在是懒,懒得敲键盘,懒得记命令,而且老忘,知道那是怎么回事儿就可以了]
另说GObject我觉得它是为了完整的模拟OO机制,
我这个最初是为了方便写OO的代码,初衷不同.
或者说我这个目前本质上是一个模板而已,
也就是说你一行行写出来typedef struct{}.....其实是一样的,估计还有不少人喜欢一行一行写的...
当然我是很希望GObject那帮疯子能接纳我的东西,呵呵...
现在正在琢磨着通过脚本来完成类的定义,这样所有的OO的机制都没问题的,就是调用起来可能会有些怪异...
Wed, 02 Feb 2011 05:19:12 -1100
@pingf:
【其实file-roller可以自动装unrar】
你可以把你的设计发到 (邮件列表)gtk-devel@gnome.org ,看看GObject那帮疯子会不会接受呢……
你的设计很不错哈!
Wed, 02 Feb 2011 06:12:48 -1100
嗯弄错了,是 gtk-devel-list@gnome.org
Thu, 24 Mar 2011 17:28:46 -1100
再次留言。。gcc有typeof关键字支持
Fri, 25 Mar 2011 03:08:32 -1100
@纵横天下:
我知道啊,这是C99的标准扩展,我这个版本的模拟也用到了,我文中的意思是在C99前的模式下可能无法用而已....