to Sna_Daniel et al:
你所说的“实现”是不是is-implemented-in-terms-of?希望不是。因为这跟Java里implements关键字正好相反。前者是实现继承(组合),后者是接口继承。你也知道,Java的接口等价与C++中的纯虚抽象类,为了避免引入多继承,Java使用这个概念来表达is-a关系。当然extends也是is-a关系,但是具有实现继承的意味。Java中间只有public inheritence,所以is-implemented-in-terms-of在Java中只能通过组合的方式完成. 如果要深究到底什么是is-a,C++ View第三期有一篇文章讲得很清楚,可以去看看。
我总结这个贴子中的观点,反对将GP视为独立思想的网友,基本上有以下两个论据:
1. STL中的所有功能都可以在典型的OO语言中"轻易"实现. 所以, GP只能被认为 是C++为了克服动态能力不足而发展起来的旁枝, 不能算作与OOP并行的主流.
2. GP只是提供了效率上的优势, 而效率相对于思想来说, 是小问题, 所以算不上独立 思想.
我想抽一点时间,比较详细地谈谈我对这个问题的认识。
首先, 尽管大家都说用动态语言可以实现STL, 可是都很清楚那只是对STL的模拟, 形似而实则不同.即便我们忽略这一点, 实际上也没有什么动态语言模拟出来的STL能够算作比较成功的. 不过是一些语言爱好者寻求心理慰藉的玩具, 或者是学者们实验室里的理论秀, 比如JAL. 曾经有一Java类库叫做JGL, 算是比较成功. 请问有谁用它写过实际程序? 我还真的曾经研究过JGL, 但是很快就失望而归.实际上, 实现一个STL的全部功能绝对不像大家想得那么简单, 抽象能力上的巨大不足必须依靠繁琐的, 不安全的动态类型鉴别机制, 在庞大的单根继承树里绕来绕去, 极其费力地模拟. 而且有些东西, 比如functor adaptor, 你就是没有办法用STL那么简洁的表现方法做出来. 如此费心费力, 如果也能称的上是"轻易, 自然", 那么我可以毫不犹豫地宣称C是面向对象语言. 如果有人不信, 你可以自己试着自己做一个小小的STL, 看看没有template意味着什么.
反过来说, 即使你能够把STL模拟的绘声绘色, 神形兼备, 那又能说明什么问题呢? 别忘了STL是C++ template思想的产物, 你只不过是一个模仿者, 这里面的差距就好像电视上模仿秀里面真假刘德华之间的差距. 如果你觉得STL只不过是OO思想的自然延伸, 那么为什么OOP流行了20年, 没有产生一个象样的STL, 而template在C++中安家才5年左右, STL就一鸣惊人呢? 如果你认为有了完备的动态库的支持, 完全可以不需要STL, 那么你又怎么解释Java/C#不辞辛苦地往语言中加入generic能力的企图, 怎么解释那么多语言拥护者处心积虑地模拟一个STL的努力呢? 答案只有一个, STL以及它所展现的GP, 与以往出现的任何东西都不一样.
我们再回过头来问一个问题, 究竟一种思想达到什么程度, 可以被称为一种思想? 我们中国人大概是受到万物归于道的思想影响太深, 凡事都喜欢往上走, 抽象再抽象, 层次越来越高, 上到最顶层看, 哦, 原来GP也不过如此, 并没有逃出OO的观念啊! 大概是我的哲学水平不高, 那本康德的<纯粹理性批判> 没太读懂, 所以我没那个能力跟大家一起上到世贸大厦最顶层(哦, 对不起, 我忘了, 世贸大厦已经没了:-< ) 探讨那么玄虚的东西. 我是个程序员, 我要做的工作不是进行抽象的哲学讨论, 而是设计实际的软件, 编写能够高效、可靠运行的代码. 如果你问我GP给一个普通程序员带来的是什么感觉,我会告诉你:a whole new world!真的,我现在的目标平台是内存和
处理器速度都很有限的WinCE,跟经典的Win32差别不大。这些东西我以前也摸过,但是现在,正是因为接触过GP,我觉得我思考问题、评价设计方案甚至编写每一行代码的方式都发生了巨大的变化。看看今天的C++社区,多么具有创新能力,很多东西以前从来就没那么想过,现在敢想,而且能够给出精彩的解决方案,让人初看时不可思议,理解之后又不禁击节叫好! 我有的时候觉得,GP最吸引人的地方可能就在于这一点。
告诉我你们看了下面这段代码的感觉:
template <DWORD t_dwWinStyle = 0>
struct WinStyleTraits {
static DWORD GetWinStyle(DWORD dwWinStyle) {
return dwWinStyle == 0 ? t_dwWinStyle : dwWinStyle;
}
};
typedef WinStyleTraits<> CUserWinTraits;
typedef WinStyleTraits<WS_OVERLAPPEDWINDOW ¦ WS_VISIBLE> COverlappedWinTraits;
typedef WinStyleTraits<WS_CHILD ¦ WS_VISIBLE> CChildWinTraits;
这段代码是WTL中一个小东西的简化版本,用来向用户提供常用的Windows风格,传递到CreateWindowEx()函数中。体会一下,看看它有多聪明,想想为什么一个OOP程序员不可能主动地发明这种东西。(附带说明一下,这个类名字里虽然有Traits字样,但它Traits味道不太浓,至少我这么觉得)
再看看这里:
template <class T>
class auto_ptr {
private:
T* pointer_;
...
public:
template <class U>
auto_ptr(U* p) : pointer_(p) {}
...
}
这是典型的GP惯用法,template contructor,此中的奥妙与趣味,让人兴致盎然,而又对C++肃然起敬。
还可以举出无数例子,但结论就是,使用GP,你的设计思路变了,分析问题的角度变了,写代码的方法变了,评价程序的尺度变了,对于整个程序结构和软件构造的看法也变了,如果这时候你还告诉我,其实我没变,我的“思想”跟以前的OO还是一样的,或者我现在的思想只不过是OO思想的附庸,那么不是你疯了,就是我疯了。
面向对象作为一种伟大的软件思想,不光现在如火如荼,而且肯定将在历史上留下光辉的足迹。我很难想象以后的软件构造中没有object这个概念。但是庞大复杂的派生层次,笨拙的设计方案数量繁多、关系复杂的对象(还记得Grandy Booch说的话吗?“如果你发现手头的类不够用,请考虑增加对象的数量”),浩大而又难以实证的软件开发过程,难以忍受的资源浪费(别告诉我你的计算机有多快,你很清楚花钱买更“快”的机器是为了什么),已经让我感到,这条路不可能长久地走下去,早晚有一天,大家会改弦更张的。
最后,我想表明我对未来GP编程思想的一个基本预期:
1. 对象仍然是构造程序的基本单位。但同时,还存在抽象的操作,作为程序的另一个基本单位。在螺旋式上升的历史规律中,我们又回到了“程序 = 数据结构 + 算法”的思路上,但这回层次高多了。
2. 只有非常有限和非常清楚的派生层次存在,对象之间不在有过分复杂的关系,除了简单的派生关系和组合关系之外,其他的关系用编译时期的静态多态性完成。你的程序中只有你所需要的、最适合你这个应用的对象以及对象之间的关系,让那些冗余对象和尽惹麻烦的复杂关系见鬼。
3. 软件构造分成三个阶段:首先构造最广泛、最通用的GP组件库,这由技术实力雄厚的专业软件公司提供。其次下游软件公司(具体应用方案的提供商)使用先进的、可视化和智能化的工具构造符合具体应用的对象,界定对象间的关系。最后,让印度人用胶水把这些对象粘起来。我承认这三个阶段根今天的基本格局相同。但是由于GP的威力,效果会完全不同:高效、轻便、紧凑、清晰、便于维护。
4. 出现一种超越C++的语言,具有以下特点:
1) 编译型语言,基于C++的语义,抛弃与C的兼容,但保留方便的与C/C++ API的接口。
2) 更加清晰的语法,特别是更加简单的template语法
3) 效率不打折扣
4) template能力不仅不能打折扣,还要继续加强
5) 基于可控制GC的资源管理机制(不光是内存)
6) 一个完备的标准库