2005年8月25日星期四

变长文件管理器

这段时间做了一个变长文件管理器(类似 WinRAR,可以把多个文件装进一个文件)。原本是学校的作业,但是我也算是认真对待了的。做的过程中遇到了很多比较抽象的问题,解决过程中也确实领悟到不少有用的编程思想,看来计算机科学这玩意儿还是要多动手写才会有提高,光看书还是不够的。(程序源码和客户端放在后面,有兴趣可以去下载)

记录文件的格式类似于FAT文件系统,采用簇作为存储单位,这样比较方便对文件进行操作。虽然这次程序引入了读取参数配置,压缩文件这些原来没有涉及过的方面,但是最终还是就一个 exe。原本觉得应该把管理器的类库做成一个 DLL,供客户端来调用,但是尝试后还是发现要把所有类库用的 .h 文件倒入到客户端那边去,而我又习惯在 .h 写类的实现,所以太麻烦,只好作罢。看来以后还是要改一改编写习惯。

这次写的过程中遇到一个问题,至今也没有想到解决办法。我本想做一个类似数据库的结构,用 Struct 模拟表中的字段,Struct 的成员变量类型相当于字段类型。用链表模拟整个表,链表传入的模版就是之间声明的 Struct,这样一个链表就可以存储任意多个具有相同成员类型的数据了,在这一点上还是很像数据库的。问题是,一个数据库可以容纳任意多的表,并且每个表的结构可以不同,这一点如何用模版实现呢?最开始想到的还是用一个链表来模拟数据库,用链表来保存链表。但是这是不行的,因为模拟表的链表本身就是模版了,都具有不同的模版类型,而链表只能存储相同类型的数据。想来想去,只能用类似 .NET 中 ArrayList 的方法,把模拟表的链表转化成类似 Object 的基类,使其具有相同类型。

那么如何在 C++ 里面模拟“所有类型具有共同基类”呢?我想到的是自己写一个 Object 类:

class MyObject
{
void* dataPtr;
int size;
}

dataPtr 保存数据所在的内存地址,size 保存数据大小。装箱时,要同时传入数据本身和数据所占字节数。然后 Object 到内存中分配一个 size 大小的空间,保存数据,并记录内存地址;拆箱时,将 void* 转化成需要的类型的指针,返回值即可。

理论上要实现还是不难,但实际中这种转换很难办到。首先,C++ 对运行时动态类型转换支持并不好。比如,假设有 MyObject a = 1 ,如何实现 int b = a 呢?MyObject 怎么知道要把 void* 转换成 int* 呢?难道 int b = a.Convert(int) ,或者 int b = a.Convert("int") ?这些都不可能,C++ 不支持传入一个类型,更不可能根据字符串转换数据类型(C++ 之提供了一个动态获得类型的方法 type_id)。其次,C++ 中各种数据类型多种多样,很难只用一个 void* 一概而论。比如,要实现字符串 char* 怎么办?要实现 STL List 怎么办?

当然,要解决这些问题也不是绝对没有办法。如果 C++ 的标准就由我来制定,C++ 的所有代码就由我来写,那我完全可以自己写这个 Object,自己实现 Object 对所有类型的转换。可能有人会说,这根本不是一个办法的办法。其实,.NET 就做到了这一点,Java 就做到了这一点,我想关键还在于它们都是由一个公司开发出来的,语言的耦合度自然就比 C++ 大。耦合度大,语言确实失去了一定的自由度,但也确实更加方便。也是到现在,我才真正体会到 C# 原来是那么方便强大的一个语言。

现在再回想起初中时刚开始接触编程的那个时候,在看看现在的自己,发现自己确实在成长,曾经觉得要不可及的那些 C 语言代码,现在只是当作工具来用了。说来现在感觉自己又进入了一个新的高度,不再是原来的桌面应用程序,不再是 Flash 和 ASP,而是编译器,操作系统,文件系统,更多原理级的东西,更接近数学。当然,这也只是一个新的开始,在这条路上还有很长要去走,还有很多高度要去翻越。

变长文件管理器 RecordManager

没有评论: