思勤无邪

上学时,因我年龄最小,个头也最小,上课时,就像大猩猩堆里的猴一般。如今,这猴偶尔也把最近的一些情况写在这里。

   :: 首页 :: 联系 :: 聚合  :: 管理
  132 Posts :: 1 Stories :: 178 Comments :: 0 Trackbacks

公告

     吾日常三省吾身,曰思、曰勤、曰无邪。

积分与排名

  • 积分 - 177584
  • 排名 - 143

最新随笔

最新评论

阅读排行榜

评论排行榜


    从CSDN上读到一篇文章,深有同感,原文如下:
    传统上认为,C++相对于目前一些新潮的语言,如Java、C#,优势在于程序的运行性能。这种观念并不完全。如果一个人深信这一点,那么说明他并没有充分了解和理解C++和那个某某语言。同时,持有这种观念的人,通常也是受到了某种误导(罪魁祸首当然就是那些财大气粗的公司)。对于这些公司而言,他们隐藏了C++同某某语言间的核心差别,而把现在多数程序员不太关心的差别,也就是性能,加以强化。因为随着cpu性能的快速提升,性能问题已不为人们所关心。这叫“李代桃僵”。很多涉世不深的程序员,也就相信了他们。于是,大公司们的阴谋也就得逞了。
    这个文章系列里,我将竭尽所能,利用一些现实的案例,来戳破这种谎言,还世道一个清白。但愿我的努力不会白费。


软件工程

    一般认为,使用Java或C#的开发成本比C++低。但是,如果你能够充分分析C++和这些语言的差别,会发现这句话的成立是有条件的。这个条件就是:软件规模和复杂度都比较小。如果不超过3万行有效代码(不包括生成器产生的代码),这句话基本上还能成立。否则,随着代码量和复杂度的增加,C++的优势将会越来越明显。
    造成这种差别的就是C++的软件工程性。在Java和C#大谈软件工程的时候,C++实际上已经悄悄地将软件工程性提升到一个前所未有的高度。这一点被多数人忽视,并且被大公司竭力掩盖。
    语言在软件工程上的好坏,依赖于语言的抽象能力。从面向过程到面向对象,语言的抽象能力有了一个质的飞跃。但在实践中,人们发现面向对象无法解决所有软件工程中的问题。于是,精英们逐步引入、并拓展泛型编程,解决更高层次的软件工程问题。(实际上,面向对象和泛型编程的起源都可以追溯到1967年,但由于泛型编程更抽象,所以应用远远落后于面向对象)。
    一个偶然的机会,我突发奇想,试图将货币强类型化,使得货币类型可以采用普通的算术表达式计算,而无需关心汇率换算的问题。具体的内容我已经写成文章,放在blog里:http://blog.csdn.net/longshanks/archive/2007/05/30/1631391.aspx。(CSDN的论坛似乎对大文章有些消化不良)。下面我只是简单地描述一下问题,重点还在探讨语言能力间的差异。
    当时我面临的问题是:假设有四种货币:RMB、USD、UKP、JPD。我希望能够这样计算他们:
RMB rmb_(1000);
USD usd_;
UKP ukp_;
JPD jpd_(2000);

usd_=rmb_;//赋值操作,隐含了汇率转换。usd_实际值应该是1000/7.68=130.21
rmb_=rmb_*2.5;//单价乘上数量。
ukp_=usd_*3.7;//单价乘上数量,赋值给英镑。隐含汇率转换。
double n=jpd_/(usd_-ukp_);//利用差价计算数量。三种货币参与,隐含汇率转换。
而传统上,我们通常用一个double或者currency类型表示所有货币。于是,当不同币种参与运算时,必须进行显式的汇率转换:
double rmb_(100), usd_(0), ukp_(0), jpn_(2000);

usd_=rmb_*usd_rmb_rate;
ukp_=(usd_*usd_ukp_rate)*3.7;
double n=jpd_/((usd_*usd_jpd_rate)-(ukp_*ukp_jpd_rate))
很显然,强类型化后,代码简洁的多。并且可以利用重载或特化,直接给出与货币相关的辅助信息,如货币符号等(这点我没有做,但加上也不复杂)。
在C++中,我利用模板、操作符重载,以及操作符函数模板等技术,很快开发出这个货币体系:
template<int CurrType>
class Currency
{
public:
   Currency<CurrType>& operator=(count Currency<ct2>& v) {

   }
public:
   double _val;

};
template<int ty, int tp>
inline bool operator==(currency<ty>& c1, const currency<tp>& c2) {

}
 
template<int ty, int tp>
inline currency<ty>& operator+=(currency<ty>& c1, const currency<tp>& c2) {

}
template<int ty, int tp>
inline currency<ty> operator+(currency<ty>& c1, const currency<tp>& c2) {

}

总共不超过200行代码。(当然,一个工业强度的货币体系,需要更多的辅助类、函数等等。但基本上不会超过500行代码)。如果我需要一种货币,就先为其指定一个int类型的常量值,然后typedef一下即可:
const int CT_RMB=0;//也可以用enum
typedef Currency<CT_RMB>RMB;
const int CT_USD=1;
typedef Currency<CT_USD>USD;
const int CT_UKP=2;
typedef Currency<CT_USD>USD;
const int CT_JPD=3;
typedef Currency<CT_USD>USD;

每新增一种货币,只需定义一个值,然后typedef即可。而对于核心的Currency<>和操作符重载,无需做丁点改动。
之后,我试图将这个货币体系的代码移植到C#中去。根据试验的结果,我也写了一篇文章(也放在blog里:http://blog.csdn.net/longshanks/archive/2007/05/30/1631476.aspx)。我和一个同事(他是使用C#开发的,对其更熟悉),用了大半个上午,终于完成了这项工作。
令人丧气的事,上来就碰了个钉子:C#不支持=的重载。于是只能用asign<>()泛型函数代替。之后,由于C#的泛型不支持非类型泛型参数,即上面C++代码中的int CurrType模板参数的泛型对等物,以及C#不支持泛型操作符重载,整个货币系统从泛型编程模式退化成了面向对象模式。当然,在我们坚持不懈的努力下,最后终于实现了和C++中一样的代码效果(除了那个赋值操作):
assign(rmb_, ukp_);
assign(usd_, rmb_*3.7);

我知道,有些人会说,既然OOP可以做到,何必用GP呢?GP太复杂了。这里,我已经为这些人准备了一组统计数据:在C#代码中,我实现了3个货币,结果定义了4个类(一个基类,三个货币类);重载30个算术操作符(和C++一样,实现10个操作符,每个类都得把10个操作符重载一遍);6个类型转换操作符(从两种货币类到第三货币类的转换操作符)。
这还不是最糟的。当我增加一个货币,货币数变成4个后,数据变成了:5个类;40个算术操作符重载;12个类型转换操作符重载。
当货币数增加到10个后:11个类;100个算术操作符重载;90个类型转换操作符重载。
反观C++的实现,3个货币时:1个类模板;1个赋值操作符重载模板;10个算术操作符重载模板;外加3个const int定义,3个typedef。
10个货币时:1个类模板;1个赋值操作符重载模板;10个算术操作符重载模板;const int定义和typedef分别增加到10个。
也就是说C++版本的代码随着货币的增加,仅线性增加。而且代码行增加的系数仅是2。请注意,是代码行!不是类、函数,也不是操作符的数量。而C#版本的代码量则会以几何级数增加。几何级数!!!
这些数字的含义,我就不用多说了吧。无论是代码的数量、可维护性、可扩展性C++都远远好于C#版本。更不用说可用性了(那个assign函数用起来有多难看)。
    我知道,有些人还会说:货币太特殊了,在实践中这种情况毕竟少见。没错,货币是比较特殊,但是并没有特殊到独此一家的程度。我曾经做了一个读取脚本中的图形信息,并绘图输出的简单案例,以展示OOP的一些基本概念,用于培训。但如果将其细化,可以开发出一个很不错的脚本绘图引擎。其中,我使用了组合递归、多态和动态链接,以及类工厂等技术。就是那个类工厂,由于我使用了模板,使得类工厂部分的代码减少了2/3,而且没有重复代码,更易维护。关于抽象类工厂的GP优化,Alexandrescu在其《Modren C++ design》中,有更多的案例。同样的技术,还可以推广到业务模型的类系统中,优化类工厂的代码。
如果还不满意,那么就去看看boost。boost的很多库实现了几乎不可想象的功能,比如lambda表达式、BGL的命名参数等等。它为我们很多优化软件代码新思路,很多技术和方法可以促进我们大幅优化代码,降低开发成本。
    最后,如果你认为C#的最大的优势在于.net平台,那我可以告诉你,这个世界上还有一种东西叫C++/CLI,完全可以满足.net的开发,而且更好,足以擦干净.net那肮脏的屁股。不过,这将会是另外一个故事了…

posted on 2007-06-15 20:41 思勤无邪 阅读(1572) 评论(2)  编辑 收藏 引用 所属分类: C++其他与技术相关

Feedback

# re: 被误解的C++ 2007-10-22 21:22 阿铁
恩,我听说当代码达到3万行后,C++的开发效率将超过java和c#.  回复  更多评论
  

# re: 被误解的C++ 2008-01-06 11:49 akbear89
高手啊!帮帮忙,我们下周要交两个自己编的程序,可我一点还不会呢,帮帮我吧~~~~~~~~大概问题如下:
1.设计和创建实现“工资报酬”应用程序的类。这个应用程序模拟一组员工的工资支付。程序中共有三类员工:按照工作时数支付工资的雇员、按照固定的月工资支付工资的雇员和按照年工资支付工资的雇员。用户可以通过该程序向工资文件中增加新员工和显示每个员工的信息及对应的月工资。

3.设计一个教务管理系统,应具有的功能
录入学生信息,放在一个记事本文件中student1.txt。
录入学生成绩,放在一个记事本文件中, student2.txt。
录入教师信息,放在一个记事本文件中,teacher.txt。
对学生信息的查询,修改,删除,添加,并保存到相应的文件中。
对学生分数的查询,修改,删除,添加,排序,并保存到相应的文件中。
生成优秀学生的名单,并打印输出。
对教师信息的查询,修改,删除,添加,并保存到相应的文件中。

如果在这里编写不方便,可以把代码发到我得邮箱里:akbear89@sina.com
救命恩人!  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理