标题: 怎样写烂程序, 好文章啊,可惜我刚刚才翻到
性别:未知-离线 loranrowe

Rank: 3Rank: 3Rank: 3
组别 士兵
级别 奋威校尉
好贴 1
功绩 6
帖子 143
编号 17767
注册 2004-9-16


发表于 2005-3-8 14:59 资料 短消息 只看该作者
发信人: Purusa (木偶机器人), 信区: CPlusPlus
标  题: [C++珠玑]怎样写烂程序(1)
发信站: BBS 水木清华站 (Sun Mar 21 11:08:58 2004)

怎样写烂程序
作者: Andrew Koenig
对本文题目的惊鸿一瞥只会引起更多的问题而不是答案。可能有人会问,难道就算是写一
篇关于马拉客运软件的文章还有任何意义吗?不错,即使如此,本文讨论书写不干活的程
序的技术。我不想在这里解释为什么我要写这样的东西;那是我在JOOP上发表的相关文章
“什么时候写烂程序”的主题。为了讨论起见,让我们假设有时候真的有理由写一个烂程
序。
为了我们当前的目的,我们可以区分三类烂程序。一种烂到家的;另一种是时对时错的;
还有一种是看起来工作可靠实则有微妙缺陷的。我们的第一个任务是学习怎么写彻底烂到
家的程序。随后我们将审阅更微妙的出错技术。

--
  乔峰吃了一惊:“好身手,这人是谁?”回掌护身,回过头来,不由得哑然失笑,
只见对面也是一条大汉单掌斜立,护住面门,含胸拔背,气凝如●,原来后殿的佛像
之前安着一座屏风,屏风上装着一面极大的铜镜,擦得晶光净亮,镜中将自己的人影
照了出来,铜镜上镌着四句经偈,佛像前点着几盏油灯,昏黄的灯光之下,依稀看到
是:“一切有为法,如梦幻泡影,如露亦如电,当作如是观。”


※ 来源:·BBS 水木清华站 http://smth.org·[FROM: 131.252.207.*]
发信人: Purusa (木偶机器人), 信区: CPlusPlus
标  题: [C++珠玑]怎样写烂程序(2)
发信站: BBS 水木清华站 (Sun Mar 21 11:11:12 2004)

连编译都不行的程序

写一个不能编译的程序毫无挑战性。大概最容易的方法,就是交给C++编译器某种甚至根本
不是C++程序的东西,比如任意的一堆文章。
然而,虽然根本不能编译的程序不是很有用,有时候它们还是很有趣的。例如,如果我把
我自己计算机上的C++编译器拿来,让它编译一个名为a.c的文件,里面只包含foo,那么输
出是::
    CC a.c:
    “a.c”, line 1: error: bad declaration of foo-did you
                         forget a ‘;’?
    1 error

假设我们现在把这个有用的错误信息拿来当成一个程序如何?那看起来像一个好办法,可
以让编译器对我们说一些有趣的话。而结果,最终是::
    CC a.c:
    “a.c”, line 1: error: CC a : CC is not a type name
    “a.c”, line 1: error: ‘.’ used for qualification;
                                 please use ‘::’
    “a.c”, line 1: error: body of non function c
    “a.c”, line 2: error: syntax error
    “a.c”, line 2: error: syntax error
    “a.c”, line 2: error: bad declaration of line-did you
                                 forget a ‘;’
    “a.c”, line 2: error: syntax error
    “a.c”, line 2: error: syntax error
    “a.c”, line 2: error: body of non function error
    “a.c”, line 2: error: bad declaration: bad is not a type name
    “a.c”, line 2: error: declaration of :
                                 declaration is not a type name
    “a.c”, line 2: error: of foo : of is not a type name
    “a.c”, line 2: error: syntax error
    “a.c”, line 2: error: did you : did is not a type name
    Sorry, too many errors
    14 errors
倒数第二行很有趣:这个特定编译器在某个程序中遇上多于某个数目的错误以后就扔毛巾
(认输)了。
这种行为在很多场合证明是有用的。通常当一个程序产生如此多的编译错误,其中至少有
一部分是由编译器试图猜测如何纠正前面的错误引起的。
通常最好先修正编译器发现前两个错误,然后再试一遍,然后再试图一次修正它们。假设
我们把上面的诊断输出信息拿来再编译一次如何?那样我们就得到::
    CC a.c:
    “a.c”, line 1: error: CC a : CC is not a type name
    “a.c”, line 1: error: ‘.’ used for qualification;
                                 please use ‘::’
    “a.c”, line 1: error: body of non function c
    “a.c”, line 2: error: syntax error
    “a.c”, line 2: error: syntax error
    “a.c”, line 2: error: bad declaration of line-did you
                                 forget a ‘;’
    “a.c”, line 2: error: syntax error
    “a.c”, line 2: error: syntax error
    “a.c”, line 2: error: body of non function error
    “a.c”, line 2: error: CC a : CC is not a type name
    “a.c”, line 2: error: syntax error
    “a.c”, line 2: error: CC is : CC is not a type name
    “a.c”, line 2: error: is not : is is not a type name
    “a.c”, line 2: error: not a : not is not a type name
    Sorry, too many errors
    14 errors
这已经非常类似前次尝试的输出了,虽然不可否认它还不完全一样。然而,如果我们重复
这个过程,编译器的输出真的完全与其输入一样。
我们刚刚得到了一个不寻常的自生成程序: 一个导致编译器生成的诊断信息与其本身一样
的程序。我们实际上把一个没用的程序转换成了一个有用的,只需改变我们对这个程序要
干什么的期望。换言之,我们写了一个甚至无需运行的自生成C++程序。

--
  乔峰吃了一惊:“好身手,这人是谁?”回掌护身,回过头来,不由得哑然失笑,
只见对面也是一条大汉单掌斜立,护住面门,含胸拔背,气凝如●,原来后殿的佛像
之前安着一座屏风,屏风上装着一面极大的铜镜,擦得晶光净亮,镜中将自己的人影
照了出来,铜镜上镌着四句经偈,佛像前点着几盏油灯,昏黄的灯光之下,依稀看到
是:“一切有为法,如梦幻泡影,如露亦如电,当作如是观。”


※ 来源:·BBS 水木清华站 http://smth.org·[FROM: 131.252.207.*]
发信人: Purusa (木偶机器人), 信区: CPlusPlus
标  题: [C++珠玑]怎样写烂程序(3)
发信站: BBS 水木清华站 (Sun Mar 21 11:13:29 2004)

能编译但是不能链接的程序
产生无法编译的程序太容易了,一点没有挑战性。一个多少有趣的问题是写一个能通过编
译器但是导致链接器抱怨的程序。
最简单的这样一个程序是一个空文件。技术上来讲,这不是一个合法的C程序,因为每一个
C源文件至少包含一个声明。然而,这是一个词法正确的C++程序,而且很多C编译器也会接
受。
它不链接的原因,当然,在于main没在任何地方定义。显然找到这点不是什么挑战,所以
让我们看是否可能写一个以更微妙的方式链接失败的程序。
链接器的目的是匹配声明和定义。如果一个源文件声明了某物而链接器没找到定义,它就
抱怨。当然,仅声明某物是不够的:通常它还必须被用到。因此,譬如,程序::
    extern void foo();
    main()
    {
    }
将愉快地链接即使foo没在任何地方定义;该定义是不必要的除非foo实际上被调用了。即
使一个调用的确出现了,某些编译器会足够聪明地发现在某些情况下该调用永不被执行。

例如,我用的编译器接受
    extern void foo();
    main()
    {
        if (0)
            foo();
    }
不带一声抗议,而我的链接器也能正常地链接。
如果未定义的东西是一个虚拟函数,情形就变得更有趣了。编译器一般无法决定一个虚拟
函数是否会被调用,因为这样的调用可以是间接的。
因此如果我们写类似这样的东西::
    struct Base {
        virtual void f();
    };
    struct Derived: Base {
        void f();
    }
一个不包含直接引用Derived::f的程序仍可以通过一个类Base的对象来调用。
因此如果一个类的任何对象被生成的话,不管它们(函数或者对象)是否被使用,其虚拟函
数必须总是被定义。
我们可以利用这一点来写一个不链接的程序:
    struct A {
        virtual void f();
    };
    main()
    {
        A a;
    }
这里我们遇上了有利可图的发现,因为用该编译器编译这个程序在这里导出了一条看起来
与问题完全无关的信息::
    ld:  Undefined symbol
        ____vtbl__1A
我们忽视了定义A::f,这条诊断信息跟那有什么关联呢?
最终弄清楚了这个特定的编译器优化虚拟函数表的生成。从实现的观点来看,基本的想法
是每个,比如说,A类的对象包含一个指向一个虚表作为该对象属于类A的标识。该优化在
于,对包含声明类A的每一个源文件避免了编译器不得不为其产生该虚表的内容。它是通过
选取一个特定的源文件并只在该源文件里产生虚表来做到优化的。
要做到这个,它得知道有一个特殊的源文件总会存在。它通过对每一个类定义寻找一个“
奇幻”函数来获得该保证,然后在定义该特定函数的源文件中定义该虚表。这个特定的编
译器选取第一个不内联的虚函数所在的文件。
因此当编译器看见
    struct A {
        virtual void f();
    }
它意识到一定在某个源文件里存在A::f的单一定义,所以当编译该源文件的时候它会同时
生成A的虚表的定义。
当我们未书写该源文件时,我们就愚弄了编译器,使得虚表没有得到定义。当此发生时,
链接器在还没遇上对f的调用的时候就先遇上了该问题,也可能是实际上根本不存在对f的
调用。
因此我们看到甚至某些明显和链接器错误一样简单的东西有时候会表现出其实不是那么简
单。

--
  乔峰吃了一惊:“好身手,这人是谁?”回掌护身,回过头来,不由得哑然失笑,
只见对面也是一条大汉单掌斜立,护住面门,含胸拔背,气凝如●,原来后殿的佛像
之前安着一座屏风,屏风上装着一面极大的铜镜,擦得晶光净亮,镜中将自己的人影
照了出来,铜镜上镌着四句经偈,佛像前点着几盏油灯,昏黄的灯光之下,依稀看到
是:“一切有为法,如梦幻泡影,如露亦如电,当作如是观。”


※ 来源:·BBS 水木清华站 http://smth.org·[FROM: 131.252.207.*]
发信人: Purusa (木偶机器人), 信区: CPlusPlus
标  题: [C++珠玑]怎样写烂程序(4)
发信站: BBS 水木清华站 (Sun Mar 21 11:16:08 2004)

不运行的程序
因为在C++中的编译和链接检查相当严格,写不能通过这些检查的程序,远没有写那些可以
一路过关运行直到失败的程序来得有趣。
即使在这里,引起眩目的失败也是轻而易举的事。随着失败变得更微妙,产生它们就变得
更有趣。最有趣的程序就是那些看起来工作但是实际上只是因为偶然才工作的程序。
让我们从简单事情着手:一个消耗所有内存的程序。
    void loop() { loop(); }
这个小程序不干别的事,就只管调用自己。在很多C++实现中,那将消耗掉无限的内存,因
为实现将保持每一个当前调用的记录。然而,在某些实现中,这个函数将实际上永远地运
行下去,因为该编译足够聪明以至于它能认出尾递归。一个尾递归就是当一个函数在返回
前干的最后一件事情就是调用自己。这样的递归一般可以写成一条goto语句,使得我们的
loop函数等价于
    void loop()
    {
        spin: goto spin;
    }
从写烂程序的角度来说,尾递归是有用的,因为它们导致在某些编译器上行而在另一些编
译器不行的程序,特别是在缺乏大量内存的机器上。
正如所发生的,一些尾递归难以优化。优化依赖于在调用新函数之前废弃旧函数所有内存
的能力。但是,假设我们打算保留一个指向该内存的指针,比如说将其作为递归调用的参
数传递又如何?譬如,考虑下面这个有些故意设计的程序,接受两个整数,m和n,并返回
m乘以n的阶乘::
    int timesfact(int m, int n)
    {
        if (n==0)
            return m;
        return timesfact(m*n, n-1);
    }
该函数是一个完全合法的尾递归,可以重写成这样::
    int timesfact(int m, int n)
    {
        while (n != 0)
            m *= n--;
        return m;
    }
然而,如果我们把原来的程序拿过来,把它改成*指针*作为第一个参数::
    int timesfact(int *m, int n)
    {
        int mn;
        if (n==0)
            return *m;
        mn = *m * n;
        return timesfact(&mn, n-1);
    }
这样即使该函数仍然具有尾递归的形式,却不再可能进行尾递归优化了。这样的函数有很
大的机会羁绊优化,特别是因为很少有人在实际中这么写程序。
当然,这个例子不是很公平,因为它依赖于编译器来制造麻烦而不是直接制造麻烦。一个
直接得多的使程序出错的办法就是利用边界错误。

--
  乔峰吃了一惊:“好身手,这人是谁?”回掌护身,回过头来,不由得哑然失笑,
只见对面也是一条大汉单掌斜立,护住面门,含胸拔背,气凝如●,原来后殿的佛像
之前安着一座屏风,屏风上装着一面极大的铜镜,擦得晶光净亮,镜中将自己的人影
照了出来,铜镜上镌着四句经偈,佛像前点着几盏油灯,昏黄的灯光之下,依稀看到
是:“一切有为法,如梦幻泡影,如露亦如电,当作如是观。”


※ 来源:·BBS 水木清华站 http://smth.org·[FROM: 131.252.207.*]
发信人: Purusa (木偶机器人), 信区: CPlusPlus
标  题: [C++珠玑]怎样写烂程序(5)
发信站: BBS 水木清华站 (Sun Mar 21 11:17:19 2004)

由于偶然性而看起来工作的程序

考虑,比如,下面这个程序::
    main()
    {
        int a[10], i;
        for(i=0; i<=10; i++)
            a = 0;
    }
在某些机器上,这个程序看起来可以正常运行和结束。在其它机器上,它会进入一个无限
循环。原因,当然是,数组a的下标从0到9,但是循环里改变了a[10]的值。
在某些机器上,a[10]“元素”占用了一块正好没被任何其它地方使用的内存,所以这个程
序看起来能工作。在其它机器上,a[10]恰好和i所在的内存所在一样,所以当i=10时语句
a[I]=0;把i又设回了0。这样又重新开始了整个循环。
当然,在C和C++中指针和下标之间的整个关系是如此根深蒂固,很难想象改变它又不带来
一整个新的语言。
在C++里,可以把数组操作封装在类里,使得进行检查容易多了,同时能做出更高级的数据
结构。然而,如果你的目标就是要写有时候能工作而其它时间不工作的程序,很难找到比
粗心使用数组和指针更好的办法。
作为另外一个例子,假设你要实现一个数据结构,存储类Thing的对象的一个变长数组。当
然,我们可以使用一个类来把该数组对其用户隐藏起来,但是我们怎么去实现呢?
做这个的干净的办法就是定义一个类,除了其它东西以外,还包括了该数组的长度以及其
起始元素的地址::
    class Thingarray {
        // …
        Thing* data;
        int length;
        // …
    };
然后象这样分配一个数组::
    Thingarray:ingarray(int n) :
        data(new Thing[n]), length(n) {}
然而,要记住,我们这里是要写不可靠的程序。这么做的一个常见技术是坚持把length在
内存中的位置相邻放在Thing的对象们的旁边。例如,想象这样的一个结构::
    struct Buggyarray {
        int length;
        Thing t[1];
    };
现在我们使类Thingarray指向一个Buggyarray::
    class Thingarray {
        // …
        Buggyarray* data;
        // …
    };
然后我们可以象下面那样分配一个Thingarray::
    Thingarray:ingarray(int n)
    {
        data = (Buddyarray*) malloc
            (sizeof(Buggyarray) + n * sizeof(Thing));
        data->length = n;
        new (data->t) Thing[n];
    }
严格来说,这个技术是非法的,因为它访问了在Buggyarray对象范围之外的内存。然而,
因为该内存被显式算进了对malloc的调用里,它大约在很多系统下都能工作。
这一技术提供了一些真正漂亮的将在稍后失败的机会。例如,如果你试图用一个带良好排
错支持的C++编译器来运行它,该编译器将正直地抱怨超越Buggyarray::t的边界进行访问
的企图。这完全是有好处的,因为屏蔽使用这样的编译器会使得其它漏洞更加难以寻找。
不仅如此,如果有人甚至在Buggyarray中引入虚函数,结果很可能会变成一塌糊涂。原因
在于C++实现一般会在每个其类带虚拟函数的对象中存储有关虚拟函数的信息。对于一个像
Buggyarray这样的类,信息看起来不像是会放在对象的尾部。所以编译器翻译下面的声明
::
    struct Buggyarray {
        int length;
        Thing t[1];
    };
为大概是这样效果的某物::
    struct Buggyarray {
        int length;
        Thing t[1];
        void *__virtual_table_pointer;
    };
现在任何修改Buggyarray::t成员之后的数据的企图都会痛殴虚表指针。为该指针寻找适宜
的有创造性的值作为练习留给读者。

结论
写烂程序的技术要比描述它们所需要的空间多得多。本文仅仅是抛砖引玉。记住,写一个
轰然崩溃的程序几乎没有什么挑战性。
真正的乐趣在于写些看起来工作,实则隐藏了一个严重问题并仅在后来才暴露出来的程序

当然,C++提供了一套工具使得这样晦涩的问题不太容易出现。如果不是直接使用下标和指
针,而是使用一个设计良好的类库,很多这样的隐晦问题就变得明显。处理这些的办法之
一就是避免使用库。
为了同样的目的,避免能排错的编译器,以及任何能使这些问题容易找到的工具。否则你
可能会无意地得到一个实际上能工作的程序。那样还有什么挑战性呢?

--
  乔峰吃了一惊:“好身手,这人是谁?”回掌护身,回过头来,不由得哑然失笑,
只见对面也是一条大汉单掌斜立,护住面门,含胸拔背,气凝如●,原来后殿的佛像
之前安着一座屏风,屏风上装着一面极大的铜镜,擦得晶光净亮,镜中将自己的人影
照了出来,铜镜上镌着四句经偈,佛像前点着几盏油灯,昏黄的灯光之下,依稀看到
是:“一切有为法,如梦幻泡影,如露亦如电,当作如是观。”


※ 修改:·Purusa 於 Mar 21 11:20:27 2004 修改本文·[FROM: 131.252.207.214]
※ 来源:·BBS 水木清华站 http://smth.org·[FROM: 131.252.207.*]


顶部
性别:未知-离线 loranrowe

Rank: 3Rank: 3Rank: 3
组别 士兵
级别 奋威校尉
好贴 1
功绩 6
帖子 143
编号 17767
注册 2004-9-16


发表于 2005-3-8 15:25 资料 短消息 只看该作者
这篇不知道有没有转过

发信人: Version (Who makes history and why), 信区: Program
标  题: 由C#风潮想起的-给初学编程者的忠告 (转贴)
发信站: 荔园晨风BBS站 (Sat Apr 19 09:24:16 2003), 站内信件


我始终认为,对一个初学者来说,IT界的技术风潮是不可以追赶的,而且也没有能
力去追赶。我时常看见自己的DDMM们把课本扔了,去卖些价格不菲的诸如C#, VB.
Net 这样的大部头,这让我感到非常痛心。而许多搞不清指针是咋回事的BBS站友
眉飞色舞的讨论C#里面可以不用指针等等则让我觉得好笑。C#就象当年的ASP一样
,"忽如一夜春风来,千树万树梨花开",结果许多学校的信息学院成了"Web 学院
"。96,97级的不少大学生都去做Web 了。当然我没有任何歧视某一行业的意识。我
只是觉得如果他们把追赶这些时髦技术的时间多花一点在基础的课程上应该是可以
走得更远的。
几个误区
初学者对C#风潮的追赶其实也只是学习过程中经常遇到的几个误区之一。我将用一
些实际的例子来说明这些现象,你可以按部就班的看看自己是不是属于其中的一种
或者几种:
认为计算机技术等于编程技术:
有些人即使没有这个想法,在潜意识中也有这样的冲动。让我奇怪的是,许多信息
学院的学生也有这样的念头。认为计算机专业就是编程专业,与编程无关的,或者
不太相关的课程他统统都不管,极端的学生只要书上没带"编程"两个字他就不看。
其实编程只是计算机技术应用过程中一种复杂性最低的劳动,这就是为什么IT业最
底层的人是程序员(CODER)。计算机技术包括了多媒体,计算机网络,人工智能
,模式识别,管理信息系统等等这些方面。编程工作只是在这些具体技术在理论研
究或者工程实践的过程中表达算法的过程。编程的人不一定对计算机技术的了解就
一定很高。而一个有趣的现象是,不少大师级的计算机技术研究者是不懂编程的。
网上的炒作和现实中良好的工作待遇把编程这种劳动神秘化了。其实每一个程序员
心里都明白,自己这些东西,学的时候并不比其它专业难,所以自然也不会高档到
哪里去。
咬文嚼字的孔已己作风:
我见过一本女生的《计算机网络原理》教材,这个女生象小学生一样在书上划满了
横杠杠,笔记做得满满的,打印出来一定比教材还厚。我不明白的是,象计算机网
络原理这样的课程有必要做笔记?我们的应试教育的确害了不少学生,在上《原理
》这一类课程的时候许多学生象学《马列原理》一样逐字背诵记忆。这乃是我见过
的最愚蠢的行为。所谓《原理》,即是需要掌握它为什么这样做,学习why,而不
是how(怎样做)。极端认真的学生背下以太网的网线最大长度,数据帧的长度,
每个字段的意义,IP报头的格式等等,但是忘了路由的原则,忘了TCP/IP协议设计
的宗旨。总之许多人花了大量的时间把书背得滚瓜烂熟却等于什么也没学。在学习
编程的时候这些学生也是这样,他们确切的记得C++语法的各个细节。看完了C++教
程后看《Thinking in C++》(确实是好书),《Inside C++》,《C++reference
》,this C++, that C++……,然后是网上各种各样的关于C++语法的奇闻逸事,
然后发现自己又忘了C++的一些语法,最后回头继续恶补…。有个师弟就跟我说:
"C++ 太难了,学了这里忘了那里,学了继承忘了模板。"我的回答道:"你不去学
就容易了"。我并没有教坏他,只是告诉他,死抠C++的语法就和孔已己炫耀茴香豆
的茴字有几种写法一样毫无意义。你根本不需要对的C++语法太关心,动手编程就
是了,有不记得的地方一查MSDN就立马搞定。我有个结论就是,实际的开发过程中
对程序语法的了解是最微不足道的知识。这是为什么我在为同学用Basic(我以前
从没有学过它)写一个小程序的时候,只花了半个小时看了看语法,然后再用半个
小时完成了程序,而一个小时后我又完全忘记了Basic 的所有关键字。
不顾基础,盲目追赶时髦技术:
终于点到题目上来了。大多数的人都希望自己的东西能够马上跑起来,变成钱。这
种想法对一个已经进入职业领域的程序员或者项目经理来说是合理的,而且IT技术
进步是如此的快,不跟进就是失业。但是对于初学者来说(尤其是时间充裕的大中
专在校生),这种想法是另人费解的。一个并未进入到行业竞争中来的初学者最大
的资本便是他有足够的时间沉下心来学习基础性的东西,学习why 而不是how。时
髦的技术往往容易掌握,而且越来越容易掌握,这是商业利益的驱使,为了最大化
的降低软件开发的成本。但在IT领域内的现实就是这样,越容易掌握的东西,学习
的人越多,而且淘汰得越快。每一次新的技术出来,都有许多初学者跟进,这些初
学者由于缺乏必要的基础而使得自己在跟进的过程中花费大量的时间,而等他学会
了,这种技术也快淘汰了。基础的课程,比方数据结构,操作系统原理等等虽然不
能让你立马就实现一个linux(这是许多人嘲笑理论课程无用的原因),但它们能

够显著的减少你在学习新技术时学习曲线的坡度。而且对于许多关键的技术(比方
Win32 SDK 程序的设计,DDK的编程)来说甚至是不可或缺的。一个活生生的例子
是我和我的一个同学,在大一时我还找不到开机按纽,他已经会写些简单的汇编程
序了。我把大二的所有时间花在了汇编,计算机体系结构,数据结构,操作系统原
理等等这些课程的学习上,而他则开始学习HTML和VB,并追赶ASP的潮流。大三的
时候我开始学习Windows 操作系统原理,学习SDK编程,时间是漫长的,这时我才
能够用VC开发出象模象样的应用程序。我曾一度因为同学的程序已经能够运行而自
己还在学习如何创建对话框而懊恼不已,但临到毕业才发现自己的选择是何等的正
确。和我谈判的公司开出的薪水是他的两倍还多。下面有一个不很恰当的比方:假
设学习VB编程需要4个月,学习基础课程和VC的程序设计需要1年。那么如果你先学
VB,再来学习后者,时间不会减少,还是1年,而反过来,如果
先学习后者,再来学VB,也许你只需要1个星期就能学得非常熟练。
几个重要的基础课程
如果你是学生,或者如果你有充足的时间。我建议你仔细的掌握下面的知识。我的
建议是针对那些希望在IT技术上有所成就的初学者。同时我还列出了一些书目,这
些书应该都还可以在书店买到。说实在的,我在读其他人的文章时最大的心愿就是
希望作者列出一个书单。大学英语-不要觉得好笑。我极力推荐这门课程是因为没
有专业文档的阅读能力是不可想象的。中文的翻译往往在猴年马月才会出来,而现
在的许多出版社干脆就直接把E文印刷上去。学习的方法是强迫自己看原版的教材
,开始会看不懂,用多了自然熟练。吃得苦下得狠心绝对是任何行业都需要的品质
。计算机体系结构和汇编语言-关于体系结构的书遍地都是,而且也大同小异,倒
是汇编有一本非常好的书。《80x86汇编语言程序设计教程》(清华大学出版社,
黑色封面,杨季文著)。你需要着重学习386后保护模式的程序设计。否则你在学
习现代操作系统底层的一些东西的时候会觉得是在看天书。


计算机操作系统原理-我们的开发总是在特定的操作系统上进行,如果不是,只有
一种可能:你在自己实现一个操作系统。无论如何,操作系统原理是必读的。这就
象我们为一个芯片制作外围设备时,芯片基本的工作时序是必需了解的。这一类书
也很多,我没有发现哪一本书非常出众。只是觉得在看完了这些书后如果有空就应
该看看《Inside Windows 2000》(微软出版社,我看的是E文版的,中文的书名想
必是Windows 2000 技术内幕之类吧)。关于学习它的必要性,ZDNET上的另一篇文
章已经有过论述。
数据结构和算法-这门课程能够决定一个人程序设计水平的高低,是一门核心课程
。我首选的是清华版的(朱战立,刘天时)。很多人喜欢买C++版的,但我觉得没
有必要。C++的语法让算法实现过程变得复杂多了,而且许多老师喜欢用模块这一
东西让算法变得更复杂。倒是在学完了C版的书以后再来浏览一下C++的版的书是最
好的。
软件工程-这门课程是越到后来就越发现它的重要,虽然刚开始看时就象看马哲一
样不知所云。我的建议是看《实用软件工程》(黄色,清华)。不要花太多的时间
去记条条框框,看不懂就跳过去。在每次自己完成了一个软件设计任务(不管是练
习还是工作)以后再来回顾回顾,每次都会有收获。
Windows 程序设计-《北京大学出版社,Petzold著》我建议任何企图设计
Windows程序的人在学习VC以前仔细的学完它。而且前面的那本《Inside
Windows 2000》也最好放到这本书的后面读。在这本书中,没有C++,没有GUI,没
有控件。有的就是如何用原始的C语言来完成Windows 程序设计。在学完了它以后
,你才会发现VC其实是很容易学的。千万不要在没有看完这本书以前提前学习VC,
你最好碰都不要碰。我知道的许多名校甚至都已经用它作为教材进行授课。可见其
重要。
上面的几门课程我认为是必学的重要课程(如果你想做Windows 程序员)。对于其
它的课程有这样简单的选择方法:如果你是计算机系的,请学好你所有的专业基础
课。如果不是,请参照计算机系的课程表。如果你发现自己看一本书时无法看下去
了,请翻到书的最后,看看它的参考文献,找到它们并学习它们,再回头看这本书
。如果一本书的书名中带有"原理"两个字,你一定不要去记忆它其中的细节,你应
该以一天至少50页的速度掌握其要领。尽可能多的在计算机上实践一种理论或者算
法。你还可以在CSDN上阅读到许多书评。这些书评能够帮助你决定读什么样的书。
日三省乎己每天读的书太多,容易让人迷失方向。一定要在每天晚上想想自己学了
些什么,还有些什么相关的东西需要掌握,自己对什么最感兴趣,在一本书上花的
时间太长还是不够等等。同时也应该多想想未来最有可能出现的应用,这样能够让
你不是追赶技术潮流而是引领技术潮流。同时,努力使用现在已经掌握的技术和理
论去制作具有一定新意的东西。坚持这样做能够让你真正成为一个软件"研发者"而
不仅仅是
一个CODER。把最多的时间花在学习上这是对初学者最后的忠告。把每个星期玩SC
或者CS的时间压缩到最少,不玩它们是最好的。同时,如果你的ASP技术已经能够
来钱,甚至有公司请你兼职的话,这就证明你的天份能够保证你在努力的学习之后
取得更好的收益,你应该去做更复杂的东西。眼光放长远一些,这无论是对谁都是
适用的


顶部
性别:未知-离线 loranrowe

Rank: 3Rank: 3Rank: 3
组别 士兵
级别 奋威校尉
好贴 1
功绩 6
帖子 143
编号 17767
注册 2004-9-16


发表于 2005-3-8 15:46 资料 短消息 只看该作者
转最后一篇,对COM的评价让我心里直发凉...

发信人: flypen (找工作), 信区: CPlusPlus      
标  题: 对主流技术的分析和总结(转载)
发信站: BBS 水木清华站 (Wed Mar 19 16:29:09 2003)


对主流技术的分析和总结    bjhua(原作)
  
关键字     COM J2EE .NET C# C++ Java Delphi VCL MFC
  


一、引言 1
我为什么要写这篇文章 1
我的故事 2
要涉及的话题 3
二、正文 3
2.1 程序设计语言 3
2.2 桌面应用程序框架 5
2.3企业应用程序框架 6
2.4 COM技术 7
结论 9
闲话 10
给入门程序员的建议 10
印度的软件业 11
附录 11


对主流技术的分析和总结
myemail: bjhua@etang.com

一、引言
我为什么要写这篇文章
首先,我要限定我文章的范围,我讨论的问题局限于桌面应用开发领域和企业应用开发领
域,所以我的结论并不适用于整个软件开发界,比如我说C语言已经退出历史舞台,这对于
写嵌入式系统的人和编写操作系统内核的人来说显然是错了。
我写这篇文章的目的主要是:
* 简单的介绍并评价当前主流技术
* 比较当前的主流技术
* 预计技术的演变

如果你想做程序员或者已经是个程序员,你可能会面对这些困惑:
* 学什么语言呢?Delphi、C++、VB、Java、C#、PHP、Python?
* 选择什么开发工具呢?Delphi、VC、C++Builder、JBuilder?
当你已经入了门,有了一定的基础之后(可能已经通晓了几种语言),你会面临进一步的
困惑:
* MFC和VCL之间是什么关系?
* J2EE到底是什么?.Net到底是什么?两者有什么本质的区别,我应该学习哪一个呢?
* COM那么复杂,为什么很多地方都用到它?我必须学习它吗?


如果是作为一个软件公司,如果不是那么大,如果你的公司还没有一个真正的技术上的灵
魂人物,那么你也会面临同样的困惑。技术问题纷繁复杂,让你不知所从,而且真正的精
通每一项技术都需要巨大的时间和人力的投入,你怎么办?选择哪种技术作为公司的主流
技术呢?选择的方向是否正确是个关乎你的公司的生死存亡的问题。

你面临着这些困惑吗?如果是,那么请让我试着为你拨云见日。


我的故事

在我上大学之前,我从没见过计算机。大学的时候,正是Dos和FoxBASE的年代,也正是计
算机软件开发世界几件伟大的事情发上的时候:(Windows3.1、Borland C++ 3.1、Visual
Basic 1.0 的推出也是伟大的事情,但那时候我还不知道计算机为何物)Widnows95推出,
并开始应用;Visual Basic 5.0推出,开发工具中第一次出现了成熟的、被广泛应用的Au
to Code Completion技术;Java推出;ASP技术开始盛行,Windows DNA技术被理解和接受;
标准C++诞生;Visual C++6.0 推出;J2EE规范推出。
成为一个程序员对我而言并不顺利,因为我不是科班出身。我入门的程序语言是FoxBASE
,这让我一直对FoxBASE有种特殊的感情,我也正是通过Visual FoxPro3.0转写Windows程
序的,如果没有它,我也许就不会成为一个程序员了。后来,在大学期间接触到了InterD
EV,那是个写ASP程序的开发工具,还有Java,也是那时候接触的,当时有点盲目崇拜的意
思(我想我喜欢Java的一个原因可能是刚开始学C的时候很受挫折)。毕业之后,我就是凭
借着自己写的一个ASP网站找到了自己的第一份工作——说来惭愧,我从来也没有成为一个
C程序员。我真正的熟悉Java是在我翻译了一本Java数据结构的书和写了一套完整的GIS系
统之后(说起此事,我要感谢一下我的公司,但因为这些故事与本文的主题无关,所以这
里就不多说了)。再后来,我自己学习了标准C++和COM技术。
有点像履历表了是吗?提到这些,我只是希望作为读者的你能够了解一下我的知识体系,
从而能够知道我大概要讲些什么;同时也希望你能够原谅我可能犯的错误——我在这里说
的话,并不一定就是最后的结论,虽然“共同探讨”这个词几乎是粗制滥造的书的作者专
用语了,但我在这里引用它是真诚的,我愿意看到你的反馈。


要涉及的话题
在开始文章的正题之前,我先大概地介绍这篇文章将会涉及到哪些知识。如果你是初学者
,希望你不要被吓倒,这虽然是一篇技术文章,但我不会过多的讨论技术细节,如果你不
懂我说的这些东西,也没关系,我本来就希望通过我的文章帮助你做出一个选择,不再走
很多人已经走过的弯路,你这要记住结论就可以了,随着你知识的增长,以后你会渐渐明
白;如果你已经通晓了这些技术或其中的大部分,那么我相信读了这篇文章你会有一些另
外的收获。
主流的程序设计语言: C++、Delphi(Object Pascal)、Java、C#
桌面应用程序框架:MFC、VCL、QT、Java AWT\SWING、.Net
企业应用程序框架:Windows DNA(ASP、COM、COM+)、J2EE、.Net Framework
开发工具:Visual Basic、Delphi、Visual C++、C++ Builder 、Visual C#

二、正文
好了,现在让我们开始我的正文吧。
首先,我来完成这篇文章的第一个目标:介绍并评价当前主流技术。我指的今天的主流技
术是:
* 程序设计语言:C++\Delphi(本来应该是Object Pascal,但为了简单,我就语言和工具
混为一谈吧)\Java\C#(虽然他刚刚推出,但因为微软为之倾注了大量心血,一定会成为一
种重要的开发语言)
* 桌面应用程序框架:MFC\VCL
* 企业应用程序框架:Windows DNA\J2EE\.Net
* COM技术:我单独提出这项技术,是因为它无法简单的被视为语言、桌面应用程序框架或
企业应用程序框架,它与这些都有关系。
2.1 程序设计语言
2.1.1 C++
语言的演进最初要从二进制代码和汇编说起,但那太遥远了。我们就从面向过程的语言说
起吧(包括Basic\C\Fortran\Pascal)。这种面向过程的高级语言终于把计算机带入了寻
常的应用领域。其中的C语言因为它的简单和灵活造就了Unix和Windows这样的伟大的软件
。面向对象的语言是计算机语言的一个合乎逻辑的进化,因为在没有过多的影响效率、简
单性的前提下提供了一种更好的组织数据的方法,可以程序更容易理解,更容易管理——
这一点可能会引出不同意见,但事实胜于雄辩,C++终于让C语言的领地越来越小,当今还
活着的计算机语言或多或少的都具备面向对象的特征,所以这一点并不会引起太多困惑。
C++的成功很大程度要归因于C,C++成为它今天的样子是合乎逻辑的产物。因为在面向过程
的时代,C几乎已经统一天下了。今天著名的语言象Java\C#都从C借鉴了很多东西,C#本来
的意思就是C++++。
其实C++曾经很有理由统一面向对象程序设计语言的天下来着,但可惜的是,C++太复杂了
。即使是一个熟练的程序员,要你很清楚的解释一些问题你也会很头痛。举几个还不是那
么复杂的例子来说:
对=的重载\成员转换函数\拷贝构造函数\转化构造函数之间有什么区别和联系呢?
这样定义一个类成员函数private: virtual void MemFun() = 0; 是什么意义呢?
int (*(*x(int))[4])(double); 是什么意思?
还有其他的特征,比如说可以用来制造一种新语言的typedef和宏(虽然宏不是C++的一部
分,但它与C++的关系实在太密切了),让你一不小心就摔跤的内存问题(只要new 和del
ete就可以了吗?有没有考虑一个对象存放在容器中的情况?)……诸如此类,C++是如此
的复杂以至于要学会它就需要很长的时间,而且你会发现即使你用C++已经好几年了,你还
会发现经常有新东西可学。你想解决一个应用领域的问题——比如说从数据库里面查询数
据、更改数据那样的问题,可是你却需要首先为C++头痛一阵子才可以,是的,你精通C++
,你可以很容易的回答我的问题,可是你有没有想过你付出了多大的代价呢?我不是想过
分的谴责C++,我本人喜欢C++,我甚至建议一个认真的开发普通的应用系统的程序员也去
学习一下C++,C++中的一些特性,比如说指针运算\模板\STL几乎让人爱不释手,宏可以用
几个字符代替很多代码,对系统级的程序员来说,C++的地位是不可替代的,Java的虚拟机
就是C++写的。C++还将继续存在而且有旺盛的生命力。


2.1.2 Java和C#
Java和C#相对于C++的不同最大的有两点:第一点是他们运行在一个虚拟环境之中,第二点
是语法简单。对于开发人员而言,在语法和语言机制的角度可以把Java和C#视为同一种语
言。C#更多的是个政治的产物而不是技术产物。如果不是Sun为难微软的话,我想微软不会
费尽心力推出一个和Java差不多的C++++,记得Visual J++吗,记得WFC吗?看看那些东西
就会知道微软为Java曾经倾注了多少心血。而且从更广泛的角度来说,两者也是非常相似
的——C#和Java面对的是同样的问题,面向应用领域的问题:事务处理、远程访问、Web
service、Web页面发布、图形界面。那么在这一段中,我暂且用Java这个名字指代Java和
C#两种语言——尽管两者在细节上确实有区别。
Java是适合解决应用领域的问题的语言。最大的原因Java对于使用者来说非常简单。想想
你学会并且能够使用Java需要多长时间,学会并且能够使用C++要多长时间。由于Java很大
程度上屏蔽了内存管理问题,而且没有那么多为了微小的性能提升定义的特殊的内容(比
如说,在Java里面没有virtual 这个关键字,Java也不允许你直接在栈上创建对象,Java明
确的区分bool和整型变量),他让你尽量一致的方式操作所有的东西,除了基本数据类型
,所有的东西都是对象,你必须通过引用来操作他们;除了这些之外,Java还提供了丰富
的类库帮助你解决应用问题——因为它是面向应用的语言,它为你提供了多线程标准、JD
BC标准、GUI标准,而这些标准在C++中是不存在的,因为C++并不是直接面向解决应用问题
的用户,有人试图在C++中加入这些内容,但并不成功,因为C++本身太复杂了,用这种复
杂的语言来实现这种复杂的应用程序框架本人就是一件艰难的事情,稍后我们会提到这种
尝试——COM技术。渐渐的,人们不会再用C++开发应用领域的软件,象MFC\QT\COM这一类
的东西最终也将退出历史舞台。

2.1.3 Delphi
Delphi是从用C++开发应用系统转向用Java开发应用系统的一个中间产物。它比C++简单,
简单的几乎象Java一样,因为它的简单,定义和使用丰富的类库成为可能,而且Delphi也
这么做了,结果就是VCL和其他的组件库。而另一方面,它又比运行于虚拟环境的java效率
要高一些,这样在简单性和效率的平衡之中,Delphi找到了自己的生存空间。而且预计在
未来的一段时间之内,这个生存空间将仍然是存在的。可以明显的看出,微软放弃了这个
领域,他专注于两方面:系统语言C++和未来的Java(其实是.Net)。也许这对于Borland来
说,是一件很幸运的事情。如果我能够给Borland提一些建议的话,那就是不要把Delphi弄
得越来越复杂,如果那样,就是把自己的用户赶到了C++或Java的领地。在虚拟机没有最终
占领所有的应用程序开发领域之前,Delphi和Delphi的用户仍然会生存得很好。


2.2 桌面应用程序框架
目前真正成功的桌面应用程序框架只有两个,一个是MFC,一个是VCL,还有一些其他的,
但事实上并未进入应用领域。遗憾的是我对两个桌面应用程序框架都不精通。但这部不妨
碍我对他做出正确的评价。
2.2.1 MFC
MFC(还有曾经的OWL)是SDK编程的正常演化的结果,就象是C++是C的演化结果一样。MFC
本身是一件了不起但不那么成功的作品,而且它过时了。这就是我的结论。
MFC凝聚了很多天才的智慧——当然,OWL和VCL也一样,侯捷的《深入浅出MFC》把这些智
慧摆在了我们的面前。但是这件东西用起来估计不会有人觉得很舒服,如果你一直在用Ja
va、VB或者Delphi,再回过头来用MFC,不舒服的感觉会更加强烈。我不能够解释MFC为什
么没有能够最终发展成和VCL一样简单好用的桌面程序框架,也许是微软没精力或者没动力
,总之MFC就是那个样子了,而且也不会再有发展,它已经被抛弃了。我有时候想,也许基
于C++这种复杂的语言开发MFC这样的东西本身就是错误的——可以开发这样的一个框架,
但不应当要求使用它的人熟悉了整个框架之后才能够使用这个系统,但很显然,如果你不
了解MFC的内部机制,是不太可能把它用好的,我不能解释清楚为什么会出现这种现象。

2.2.2 VCL
相比之下VCL要成功的得多。我相信很多使用VCL的人可能没有像MFC的用户研究MFC那样费
劲的研究过VCL的内部机制。但这不妨碍他们开发出好用好看的应用程序,这就足够了,还
有什么好说的呢?VCL给你提供了一种简单一致的机制,让你可以写出复杂的应用程序。在
李维的Borland故事那篇文章中曾经说过,在Borland C++3.1推出之后Borland就有人提出
开发类似C++ Builder一类的软件,后来竟未成行。是啊,如果C++Builder是在那个时候出
现的,今天的软件开发领域将会是怎么样的世界呢?真的不能想象。
也许再过一段时间,这些都将不再重要。因为新生的语言如Java和C#都提供了类似于VCL
的桌面应用程序框架。那个时候,加上Java和C#本身的简单性,如果他们的速度有足够块
,连Delphi这种语言也要消失了,还有什么好争论的呢?只是对于今天的桌面程序开发人
员来说,VCL确实是最好的选择。
2.3企业应用程序框架
2.3.1 Windows DNA
Windows DNA的起源无从探究了。随着.Net的推出,事实上Windows DNA将成为历史的陈迹
。Windows DNA虽然是几乎所有的企业应用程序开发人员都知道的一个名词,但我相信Win
dows DNA事实上应用的最广泛的是ASP而不是COM+。真正的COM开发有多少人真正的掌握了
呢,更不要提COM+(我有必要解释一下:COM+是COM的执行环境,它提供了一系列如事务处
理、安全等基础服务,让应用程序开发人员尽量少在基础架构设计上花精力)——当然我这
里指的COM开发不是指VB下的COM开发,所以要这么说,是因为我觉得如果不能理解用C++进
行COM开发,也就不能真正的理解COM技术。如果以一种技术没有被广泛理解和应用作为失
败的标志,那么Windows DNA实际上是失败了,但这不是它本身的错,而是基于C++的COM技
术的失败造成的。多层应用、系统开发角色分离的概念依然没有过时。
2.3.2 J2EE
J2EE是第一套成功的企业应用程序开发框架。因为它把事务处理、远程访问、安全这些概
念带入了寻常百姓家。这种成功我认为要归因于Java的简单性。Java的简单,对于J2EE容
器供应商来说一样重要。开发一个基于Java的应用服务器要比基于C++的更容易。而且由于
Java的简单性,应用系统开发者出错的机会也会少一些,不会像C++的开发者那样受到那么
多挫折。开发基于Java的企业应用系统的周期会更短,这恐怕是不容争辩的事实。不论如
何,是J2EE让事务处理、远程访问、安全这些原来几乎都是用在金融系统中的概念也被一
般的企业用户使用并从中获得利益。
2.3.3 .NET
.Net有什么好说的呢?其实,它不过是微软的J2EE。事务处理、安全、远程访问,这些概
念在.Net中都找得到。更有力的说明是,微软也利用了.Net实现了一个Pet Store。所以,
.Net与J2EE几乎是可以完全对等的。但微软确实是一家值得尊敬的公司——我指从技术上
,象Web form这种东西,我相信很多Web应用开发者都梦想过甚至自己实现过,但Sun却一
直无动于衷,而且似乎Borland也没有为此作过太多努力,好像有过类似的东西,但肯定是
不怎么成功——Borland已经很让人敬佩了,我们也许无法要求太多。
2.4 COM技术
COM应当是个更广泛的词汇,其实我觉得AxtiveX、OLE、Automation、COM+都应当提及,因
为如果你不理解COM,上面的东西你是无法理解的。而且,我只是想说明COM是一种即将消
亡的技术,仅仅说说COM的复杂性和他的问题就够了,所以不会提及那些东西。
为什么会出现COM技术?COM的根本目标是实现代码的对象化的二进制重用,进而实现软件
的组件化、软件开发工作的分工。这要求他做到两点:第一,能够跨越不同的语言,第二
,要跨越同一种语言的不同编译器。COM技术为这个目标付出了沉重的代价,尤其是为了跨
越不同的编译器,以至于无论对于使用者而言还是开发者而言,他都是一个痛苦的技术。
但幸运的事,这一切终归要结束了。
让我们从这个目的出发看看COM为什么会成为它现在的样子。
其实COM不是什么新玩意,最初的DLL就是重用二进制代码的技术。DLL在C的年代可能还不
错,但到了C++的年代就不行了。原因在于如果你在.h文件中改变了类定义(增加或者减少
了成员变量),代码库用户的代码必须重新编译才可以,否则用户的代码会按你的旧类的
结构为你的新类分配内存,这将产生什么后果可想而知。这就是为什么通过接口继承和通
过接口操作对象成为COM的强制规范的原因,能够通过对象的方式组织代码是COM的重要努
力。
那么著名的IUnknown 接口又是怎么回事呢?这是为了让使用不同编译器的C++开发人员能
够共享劳动成果。首先看QueryInterface,因为COM是基于接口的,那么一个类可能实现了
几个接口,而对于用户来说,你又只能通过操作接口来操作类,这样你必须把类造型成某
个特定的接口,使用Dynamic_cast吗?不行,因为这是编译器相关的,那么,就只好把它
放在类的实现代码中了,这就是QueryInterface的由来。至于AddRef和Release,他们产生
的第一个原因是delete这个操作要求一个类具有虚析构函数(否则的话,他的父类的析构
函数将不会被调用),但不幸的是不同的编译器中虚析构函数在vtbl中的位置并不相同,
这就是说你不能让用户直接调用delete,那么你的COM对象必须提供自己删除自己的方法;
另外的原因在于一个COM对象可能作为几个接口在被用户同时使用,如果用户粗暴的删掉了
某个接口,那么其他的接口也就不能用了,这样,只好要求用户在想用一个接口的时候通
过AddRef通知COM对象“我要使用你了,你多了一个用户”,而在不用之后要调用Release
告诉COM对象“我不用你了,你少了一个用户”,如果COM对象发现自己没有用户了,它就
把自己删掉。
再看看诡异的HRESULT,这是跨语言和跨编译器的代价。其实,异常处理是物竞天择的结果
——连一直用效率作标榜的C++都肯牺牲效率来实现这个try-catch,可见它的意义,但CO
M为了照顾那些低级的语言居然抛弃了这个特征——产生的结果就是HRESULT。我们可以看
看他是多么愚蠢的东西。首先,我们要通过一个整数来传递错误信息,通过IErrorInfo来
查找真正的错误描述,本来在现代语言中一个try-catch可以解决的问题,现在我们却需要
让用户和开发者都走很多路才能解决,你怎么评价这个结果?其次,由于这个返回计算结
果的位置被占用了,我们不得不用怪异的out参数来返回结果。想想一个简单的 int add(
int op1,int op2)在COM中竟然要变成HRESULT add(int op1,int op2,int *result),我不
知道你对此作何感想。而且由于COM的方法无法返回一个对象而只能返回一个指针,为了完
成一个简单的std::string GetName()这一类的操作,你要费多少周折——你需要先分配一
块内存空间,然后在COM实现中把一个字符串拷贝到这个空间,用完了你要删掉这个空间,
不知道你是否觉得这种工作很幸福,反正我觉得很痛苦。
还有COM为了照顾那些解释性的语言,又加入了Automation技术,你有没有为此觉得痛苦?
本来一个简单的方法调用,现在却需要传给你一个标志变量,然后让你根据这个标志变量
去执行相应的操作。(这一点我现在仍然不明白,为什么解释性的语言需要通过这个方式
来执行一个方法)。
“我受够了,我觉得头痛”,你会说,是啊,我想所有的人都受够了,所有这些因素实际
上是把COM技术变成了一头让人无法驾驭的怪兽。人对复杂事物的掌控能力终究是有限的,
C++本身已经够复杂了, COM的复杂性已经超出了我们大部分人的控制能力,你需要忍受种
种痛苦得到的东西与你付出的代价相比是不是太不值得了?我们学习是为了解决问题,而
现在我们却需要为了学习这件事情本身耗费太多的精力。这些痛苦的东西太多了,我在这
里说到的,其实只是一小部分而已。计算机技术是为人类服务的,而不是少数人的游戏(
我想COM技术可能是他的设计者和一部分技术作者的游戏),难道我们愿意成为计算机的奴
隶吗?通过一种过于复杂的技术抛弃所有的人其实等于被所有的人抛弃,这么多年中选择
J2EE的人我相信不乏高手,你是不是因为COM的过于复杂才选择J2EE的?因为它可以用简单
的途径实现差不多的目标——软件的“二进制”重用、组件化、专业分工(容器开发商和
应用开发商的分工)。事实上,你是被微软所抛弃的,同时,你也抛弃了微软。
现在让我们回来吧,我把你带进了COM的迷宫,现在让我把你领回来。再让我们看看COM到
底想实现什么目标,其实很简单,不过是代码的二进制重用,也就是说你不必给别人源代
码,而且你的组件可以象计算机硬件那样“即插即用”。我们回过头来看看Java,其实,
这种二进制重用的困难是C++所带来的(这不是C++本身的错,而是静态编译的错),当Ja
va出现的时候,很多问题已经不存在了。你不需要一个头文件,因为Java的字节码是自解
释的,它说明了自己是什么样子的,可以做什么事情,不像C++那样需要一个头文件来解释
这些事情;也不需要事先了解对象的内存结构,因为内存是在运行的时候才分配的。
如果我们现在再回过头来解决COM要解决的问题,你会怎么做呢?首先你会不再选择C++这
种语言来实现代码的“二进制”重用,其次,你会把所有的语言编译成同样的“二进制”
代码(实际上,应当说是字节码),这显然是更聪明的做法,从前COM试图在源代码的级
别抹平二进制层次的差异,这实际上是让人在做本来应当由机器做的事情,很愚蠢是吗?
但他们一直做了那么多年,而且把这个痛苦带给了整个计算机世界——因为他们掌握着事
实的标准,为了用户,为了利润,为了能够在Windows上运行,尽管你知道你在做着一个很
不聪明的事情,但你还是做了。
COM技术为了照顾VB这个小兄弟和实现统一二进制世界的野心,实在浪费了太多的精力。首
先,落后的东西的消亡是必然的,就象C、Pascal在应用领域的消亡一样,Basic一点一点
的改良运动是不符合历史潮流的做法,先进的东西和落后的东西在一起,要么先进的东西
被落后的东西拖住后腿,要么是同化落后的东西,显然我们更愿意看见后者,现在Basic终
于被现代的计算机语言同化了。其次,统一二进制世界好像不是那么简单的事情,而且也
没什么必要,微软的COM技术奋战了10年,现在也只有他自己和Borland支持,.Net终于放
弃了这个野心。这一切终于要结束了。过去J2EE高歌猛进地占领着应用开发的领地,COM在
这种进攻面前多少显得苍白无力。现在微软终于也有了可以和J2EE一较长短的.NET,对于
开发人员来讲,基于字节码的组件的二进制重用现在是天经地义的事情;你不用再为了能
够以类方式发布组件做那么多乱七八糟的事情,因为现在所有的东西本来就是类了;实现
软件开发的分工也很自然,你是专业人员,就用C#吧,你是应用开发人员,你喜欢用VB.N
et,你就用吧,反正你们写的东西最终都被翻译成了一样的语言(其实我觉得这一点意义
不大,因为一些不那么好用的语言被淘汰是正常的事情,C风格成为程序设计语言的主流风
格,肯定是有它的原因的,语言的统一其实是大势所趋,就象中国人民都要说普通话一样,所?br /> 晕揖醯肑ava不支持多语言算不上缺点——本来就是一种很好看很好用的语言了,为什么要
把简单问题复杂化呢?)。
COM不会在短期内死去,因为我估计微软还不会马上用C#开发Office和Windows的图形界面
部分,但我相信COM技术退出历史舞台的日子已经不远了,作为一般的开发人员,忘了这段
不愉快的历史吧——你将不会在你的世界里直接和COM打交道。
若干年以后,我想COM也许会成为一场笑话,用来讽刺那种野心过大、钻牛角尖的愚蠢的
聪明人。

结论

说了很多,应该是有个结论的时候了。我似乎做了一件冒天下之大不韪的事情,因为我评
价了主流技术,还要试图进行比较,好像某个名人说过:“C++Builder也好,Visual C++
也好,能在市场上立足,肯定都是有自己的过人之处的,而且一个人精通数种开发语言、
数种开发工具是不可能的事情”,言下之意就是说你不要对这些东西妄加评论,但怎么可
以不评论?好像高手都不屑于说哪种语言好、哪种语言坏,我不知道什么时候形成了这种
风气。简单地说C++比Java好或者Java比C++好显然是愚蠢的行为,但如果让你用Java写驱
动程序,用C++开发一个MIS系统是不是愚蠢的行为呢?显然更愚蠢。我想,作为一个独立
的能思考的人,外界的东西对你而言总是有好有坏,而且你的生命有限,你还要享受你的
生活,所以你必须做出选择。所以,起码评价这些东西对我自己而言是正确的——只要我
有能力评价,那我就说出我的评价吧。

对于计算机语言来说,未来真正重要的语言只有三种C++、Java和C#。
C++将更适合于专业的计算机公司编写图形界面系统(比如KDE)、虚拟机(比如Java虚拟
机或者.Net运行环境)、杀毒软件或者其他的盒装软件(比如说Photoshop、Dream weave
r)这一类的东西。而且C++适合程序员做学习之用,能对C++有一定理解的程序员往往也应
该能更深刻的理解Java、C#,这有助于编写更好的软件。
如果是开发为客户定制的应用系统Java、C#是更好的选择。包括桌面应用和Web应用。至于
其他的语言比如VB.Net其实并没有太大的意义。
Delphi在未来一段时间将继续存在,而且活得不错。最重要的原因在于,第一它有一套丰
富的组件库,第二它效率相对算高的,第三它简单。如果虚拟机的执行效率赶不上Delphi
,它就有存在的理由,但从过去的Visual J++来看,微软的虚拟机做得确实可以很好,加
上.Net的组件库和C#的简单性并不差,所以从长远来看Delphi可能不那么乐观。
其实上面的比较也包含了桌面应用程序框架的比较。在现在来说VCL无疑最好的,MFC已经
退出历史舞台。.Net中所带的桌面应用程序框架将最终统一桌面应用领域(但不包括微软
和Borland这样的专业公司,因为他们要作出最好用而且效率最高的软件)。至于Java中所
带的桌面应用程序框架,实在让人哭笑不得。这个结论的变数是.Net运行环境的执行效率
。如果.Net中的虚拟机象Java的一样,那微软就倒霉了,它等于放弃了桌面应用开发工具
领域,但根据微软在Visual J++上的成就和他推广.Net的背水一战的驾式,.Net在桌面领
域失败的可能性不大(但不是没有,起码基于COM的技术在企业应用领域几乎可以说是全军
覆没)。
在企业应用程序框架领域,最终只有J2EE和.Net可以决一雌雄。我没有提到CORBA,它也可
以算是企业应用程序框架,但他的声势和J2EE或者.NET实在不能同日而语,而且最重要的
是只有Borland一家大公司支持它(SUN、IBM、BEA、Borland支持J2EE,微软就不用说了)
,所以就不详细说他了。
那么最终谁会赢呢?我想微软赢的可能性大一些。这样说可能让很多人不快,而且IBM的厉
害也是有目共睹的。但这并不是纯技术问题,就象Windows NT蚕食Unix的领土那样,那时
候微软也是孤军作战。J2EE的问题在于第一:混乱,第二,价高。我相信很多人都对这两
点有过不快的经历。你知道写给Weblogic的应用程序不是很顺利地就可以移植到Webspher
e上的,反过来也一样。但.Net就不一样了,那是微软一个人的作品,根本不存在移植的问
题。如果J2EE阵营不想败在这一点上,有三个办法,第一种就是通过制定统一的标准彻底
消灭移植问题,第二种是开发一种好用的部署工具(不能象JBuilder那么大、那么慢:)
,屏蔽不同的应用程序容器之间的区别,第三种,也是最不可能的,就是J2EE阵营有人能
够一统天下。显然,这三种解决办法都不太现实。
第二点价高,这是SUN、IBM、BEA、ORACLE传统,也是它们一直让微软的进攻屡屡得手的软
肋。我一直不太能明白他们的西就为什么那么贵。这样想一想:微软的.Net SDK白送给你
,BEA的Weblogic一个CPU的License两万,如果你两种技术都会,如果你给客户的系统报价
一样,你选哪种开发技术?这一点实在让人觉得无可奈何。J2EE有的东西,.Net也有(除
了不能跨平台),技术上的细微差别在巨大的价格差异面前还有什么意义呢?
当然,SUM、IBM这些大公司也不是等闲之辈。就象Windows NT没有消灭Unix一样,J2EE应
当会像Windows NT和Unix的共存一样和.Net共存,只是我想.Net恐怕会占上风。
闲话
说完了该说的技术问题,说说闲话吧。有的话放在心里觉得不说出来不舒服,且让我一吐
为快
给入门程序员的建议
不知道我在学计算机的时候是不是走了弯路。但我想如果让我重新开始学写程序的话,我
会采用一些不同的办法。如果你也正在想成为一个程序员,这些也许会对你有帮助。
我觉得可能大概要分几个阶段,第一个阶段应该是找一门简单的语言入门,比如Java或者
C#都应该比较合适,选一本简单的带例子的书(最好不要太厚),按部就班的把书学完。
这时候可能还有些懵懵懂懂,但没关系,可以开始做个小小的软件了,重要的事你要自己
用那种语言的方式想思考,如果有项目做,当然更好。之后,你会觉得有点感觉了。如果
你象我一样不是科班出身的,接下来应当补习一下计算机专业的课程,我觉得最重要的是
数据结构——那些东西你可能永远都不会自己做,C++中有漂亮的STL,Java中也为你实现
了大部分东西,但我觉得真的有必要学习那些内容,这会加强你用计算机语言思考问题的
能力。在进一步,如果你的入门语言不是C++,那你可以补习一下C++,尽管你可能永远都
不会用C++开发程序。C++在现在的计算机世界就象是普通话一样,而且它能让你很容易的
理解其他语言中难以理解的问题。
学完了C++,那你应当就已经不是一个初级程序员了,欢迎你进入计算机软件开发的世界


印度的软件业
我记得好像在CSDN上看见过一篇文章,极力的鼓吹印度的软件业。而且我记得他好像说过
一句很刻薄的话“我们公司那些B大的和T大的,一个一个特别牛,牛得看不见人……做起
界面极尽奇迹淫巧之能事……”,诸如此类,总之认为程序员只有象印度的高中生那样乖
乖的、懂得UML、会看Function Specification才算是真正的程序员。我当时觉得很不舒服
。我想这个人应该不是B或T大的——哦,别误会,我也不是——但我觉得好像B大的T大的
人没象他说的那样。而且我不明白为什么中国的软件业为什么一定要向印度看齐?作为一
家公司,你想获取商业利润,学习印度无可厚非,你大可以找一大堆高中生培训成编程蓝
领(我没有轻视高中生的意思,我相信有很多“高中生”在技术领域取得的成就是让我望
尘莫及的),但你不应该因此就把有血有肉有个性的程序员扁得一钱不值。说实话,所谓
的编程蓝领不过是工厂里面的装配工,如果有一天工厂里面换了自动化的设备,这些人就
全成了废人!而你要知道并不是这些装配工发明了自动化机器。我想这种话用不着多说,
子曰“过犹不及”,你可以喜欢变成蓝领,但不要把问题推向极端,把问题推向极端往往
就会犯错误。我们中国可以在某种程度上学习印度,但好像我们更应该学习美国——只是
我们现在没那么富裕——可是微软也不是从一开始就是这样一个伟大的帝国的,IBM也一样。



附录
参考书目
阅读如下图书有助于理解本文内容。而且这些书都是好书,值得一读。
* 《标准C++宝典》
* 《C++编程思想》
* 《深入浅出MFC2e》
* 《COM技术内幕》
* 《COM本质论》
* 《Java编程思想》
* 《精通EJB》第二版
* 《J2EE编程指南》
* 《Delphi 6开发人员指南》
* 《C#宝典》
* 《微软 .Net战略》


--
************

如果生活的曲线是这样: ──────────── 。


※ 来源:·BBS 水木清华站 smth.org·[FROM:  61.149.1.192]
顶部
性别:未知-离线 loranrowe

Rank: 3Rank: 3Rank: 3
组别 士兵
级别 奋威校尉
好贴 1
功绩 6
帖子 143
编号 17767
注册 2004-9-16


发表于 2005-3-8 15:50 资料 短消息 只看该作者
最后最后是一些学习c++用的书,同样是别人的推荐  

1. C++ Primer (3/e), Lippman/A.W./1998
(听说 1999 将有中译本)
(转载,候捷 语)
2. The C++ Programming Language (3/e), Bjarne/A.W./1997
(听说 1999 将有中译本)

以上两本书是 C++ 经典百科。就内容水平而言,我认为同为瑜亮。 普遍的印象是,第一本较易接受,第二本涩味稍重。第二本书 作者 Bjarne 是 C++ 语言的创造者,所以有其权威性。我认识的多 位 C++/OOP 高手,都是两书齐具。

3. Inside The C++ Object Model, Lippman/A.W./1996
(中译本 <深度探索 C++ 物件模型>)

全书讲解 C++ object model,上穷碧落下黄泉。内容很好,层次也高, 可惜原文书大大小小的错误繁如晨星,阅读时需小心。

4. Effective C++, Meyers/A.W./1992
(印象似有中译本,名称忘了,谁可补充说明?)

5. More Effective C++, Meyers/A.W./1996
(有中译本吗?我不知道,谁可补充说明?)

同一作者的这两本书,专讲 C++ programming 的重要观念,使你的程式 更稳健更有效率。书中许多观念涉及 C++ object model,与 (3) 书混合看, 如鱼得水。

6. Polymorphism in C++ <多型与虚拟> 侯俊杰/松岗/1998
(没有中译本 -- 它本身就是中文书)

在语法粗具的基础上,直接把读者导引到最核心最重要的思想,并且 在建立这个思想的过程中,提供足够的必要基础。


我只列出一本中文书,是因为这方面的中文书我看得少,英文书看得多。「恐有遗珠之憾」这类「八方得体」的话,还是说一下好了 。
注意,这些都只是强本固元用来扎基础的书籍而已,要观摩大型程式经验,还有诸如 Large Scale C++ Software Design(John Lakos/A.W./1996)可以阅读。

OO 的世界,不止 OOP,还有 OOA/OOD,那又是一缸子的学问和一缸子的书

ps:
以前挖的那个坑,过了三月一定继续填土,现在实在没时间...
顶部
性别:未知-离线 Maxwell

代王
监管使
枢密直学士
山南西道节度使

Rank: 27Rank: 27Rank: 27Rank: 27Rank: 27Rank: 27
柱国(正二品)
组别 诸侯
级别 征东将军
好贴 4
功绩 1845
帖子 5800
编号 622
注册 2004-7-7


发表于 2005-3-8 20:26 资料 文集 短消息 只看该作者
几篇文章都不错,最后一个书目估计有一部分是抄的侯捷的,觉得很眼熟。

1. C++ Primer (3/e), Lippman/A.W./1998
(听说 1999 将有中译本)
这个估计是指繁体中文版,简体中文版2002年才出版
2. The C++ Programming Language (3/e), Bjarne/A.W./1997
这本我似乎至今没有见到简体中文版

4. Effective C++, Meyers/A.W./1992
(印象似有中译本,名称忘了,谁可补充说明?)
这个确实有中文版,而且很早就有(现在好像新出了一个版本),我在图书馆看到的时候已经旧的不成样子了,好像是XX的五十个技巧还是什么名字。


曾经有一段时间大陆的程序员奉侯捷先生的话如圣旨一般,提领这个词印象中就是他普及过来的,终于现在冷静了下来,说明这个群体又成熟了一点。侯捷先生影响了一代程序员,呵呵。
顶部
性别:未知-离线 晨山尚书
(呼吸氧气)

白衣伯爵中大夫

Rank: 20Rank: 20
组别 翰林学士
级别 大将军
好贴 4
功绩 312
帖子 11210
编号 1080
注册 2004-10-28
来自 海峡西岸
家族 慕容世家


发表于 2005-3-9 14:40 资料 文集 短消息 只看该作者
这些能叫烂游戏吗?文章挺实用的.
顶部

正在浏览此帖的会员 - 共 1 人在线




当前时区 GMT+8, 现在时间是 2025-2-5 21:55
京ICP备2023018092号 轩辕春秋 2003-2023 www.xycq.org.cn

Powered by Discuz! 5.0.0 2001-2006 Comsenz Inc.
Processed in 0.034769 second(s), 10 queries , Gzip enabled

清除 Cookies - 联系我们 - 轩辕春秋 - Archiver - WAP