为什么使用C++(1)


从这点上来说,我们可以模糊地把应用分为两类(当然前提是我们只关心C/C++,不关心java/C#/ruby/erlang等):低水平应用和高水平应用。低水平应用的意思就是,在这里并不需要那些梦幻抽象如OB(基于对象)/OOP和GP;高水平的意思当然就是需要了。显然,在所有需要C/C++的领域(由于它们的高效性)里,有大量“高水平”应用(参看在Bjarne Stroustrup主页上列出的),在这些领域,C++就会更有用。

不过,换个角度想想,即使在这些领域,程序员在他们的代码中不使用那些高水平的抽象,还是有他们应该使用C++的理由。为什么呢?因为你的代码不使用类和模板并不意味着不使用类库。考虑所有便捷的C++类库工具(即将有校准扩展tr1/tr2)的实用性,我认为在这些情况下,有非常充分的理由选择C++——编码的时候你可以仍然使用C的形式(以任何你想要的方式来保持KISS)。同时,你还可以使用强大的C++类库(例如,STL标准模板库,tr1/tr2组件等)。最终,就会发现这件可能会被很多人忽略的事情——有时KISS依靠抽象。我想,Matthew Wilson在他的新书“Extended STL,Vol1”的序言中,极其透彻地阐明了这个观点。书中提到了两段代码,分别用C和C++编写:

//C代码
DIR*  dir = opendir(".");
if(NULL != dir)
{
  struct dirent*  de;
  for(; NULL != (de = readdir(dir)); )
  {
    struct stat st;
    if( 0 == stat(de->d_name, &st) &&
        S_IFREG == (st.st_mode & S_IFMT))
    {
      remove(de->d_name);
    }
  }
  closedir(dir);
}

//C++代码
readdir_sequence entries(".", readdir_sequence::files); 
std::for_each(entries.begin(), entries.end(), ::remove); 
And it’s even simpler in C++09: 
// C++09代码
std::for_each(readdir_sequence(".", readdir_sequence::files), ::remove);

我想,这能很清楚地说明,为什么即使人们不需要使用类和模板的时候还是应该使用C++——你会发现便捷的C++类库是多么有用。类似地,如果一个高效的容器(或者一个巧妙的指针)可以使你摆脱所有手工操作内存的麻烦工作,那么,还有什么理由要使用那些原始的malloc/free?如果一个好的string类(我不是在说std::string;人人都知道这不是C++做的最好的)或者regex类可以使你摆脱所有你看都不想看的混乱的字符串处理代码,那么还有什么理由要选择手动做这件事情呢?如果一个“transform”(或‘for_each’)语句可以如此简单明了地一行就完成你的工作(当然,我知道C++做这件事需要lambda函数的支持),那么,还有什么理由要手动写for-loops循环?如果高定制的函数真的能实现你想要的功能,那么,还有什么理由使用笨拙的工作区来完成同样的事务呢?

KISS并不意味着“粗糙”;KISS的意思是为你的工作选择最适合的工具,“最适合”意味着你所使用的工具能尽可能直接(和简洁)的帮助你表达你的想法。只要它不影响代码的可读性和易懂性。

现实问题

人们可能会说C++很容易会用错,而相反,C通常更容易管理和操控。一个中等水平的C++程序员可能会写出一大串联系紧密的类,而很快这些类就会变成一堆垃圾。但这实际上只是个别情况。一方面,在任何面向对象语言中都会经常发生这样的事情。总是有一些程序员,他们敢于在类之上再定义类,而他们甚至还不知道什么是HAS-A和IS-A;他们学习了所有定义一个类和从其他类继承一个类的语法,他们就觉得掌握了OOP的本质。另一方面,为什么问题会出现在C++中,是因为C++有很多阻止设计的复杂之处,是因为C++如此灵活,以至于每个用C++解决的问题都有很多可选的解决方案(考虑所有的GUI类库),以至于权衡选择哪种解决方案就成了艰巨的工作。C++的附属复杂性是一个历史遗留问题,C++0X做了多番努力试图摆脱这个问题;关于设计的灵活性并不是一件坏事——如果你考虑到它可以帮助好的设计师做出好的设计;如果有人谴责它,因为这样浪费了自己很多脑细胞,那这只是个人问题,而不是语言问题,或许这样的人就不应该负责做设计。如果你担心你的C++编程伙伴因为受这些高水平特征的诱惑而使得你的工程代码一团遭,那么,或许你应该建立一个编码标准并强制执行它(或者你可以遵循the collective wisdom,或者坚持C规范,或者带有C++类的C规范),而不是因为存在风险而退缩放弃(政策可以避免风险),因为如果不这样做,你将再也不能接触所有C++类库

另一方面,存在着最重要的心理上问题——如果一个语言中存在一个稀奇古怪的性质,那么最终就会有人发现它,然后人们就会被它吸引,这就会吸引那些本来在努力做一些有用的事的人的精力(有点像墨菲法则),不要去打扰那些正在做完美解决方案的人。人们天生就会被一些稀有资源吸引。结论就是:诀窍和稀奇古怪的性质就是稀有资源,所以会引起人们的注意,更不必说掌握一种诀窍可以使人感觉自己与众不同。糟糕的是,即使是没有价值的诀窍也会引起人们的强烈注意。

C++里有多少技巧?C++里有多少诀窍?总之,C++有多少复杂之处?

公平地说,大多数窍门和技巧在最近几年都已经被发现了(例如,modern C++),已经用在了真实需求中,特别是实现高灵活性和属性类库组件的需求(考虑所有在boost中的组件)。它们确实(在一些程度上说)引导了一些现实问题的完美解决方案。可以这样考虑这件事情:如果你处在这样一种情况下,你得使用窍门来实现一些确实有用的事情;或者你不使用窍门实现它,那么其他人就不会从使用它上得到好处。你会选择哪种?我想聪明的人会选择前一种,不管窍门有多难,实现有多麻烦。

但是所有的争论都不能改变这样的事实:那就是我们值得拥有一种可以在代码中干净地表达我们的想法的语言。以boost.function/boost.bind/boost.tuple为例,variadic templates(可变模板)可以很容易地(通过减少通信线路为原来的十分之一)实现这三个(将来会更多)类库,代码会变得简洁,尽可能地简单。Auto, initializer-list, rvalue-reference, template-aliasing, strong-typed enums, delegating-constructors, constexpr, alignments, inheriting-constructors,等;所有这些C++0X的特性,它们都有一个共同的目标——去除语言中的各种附属复杂性或阻碍

就像Bjarne Stroustrup说的,显然,C++太复杂;显然,人们有些恐惧它而放弃它。但是“人们也需要相对复杂的语言来处理绝对复杂的问题”。我们不可能减少语言的特性来使语言变得更有力。像是模板这样复杂的特性,或是更复杂的多重继承,这些可能会对你的需求更有用,你只需要非常认真、必要地了解它们,这样就不会搬起石头砸到自己的脚。在C++的所有复杂性中,唯一妨碍我们的就是附属复杂性(有人称它为“阻碍”),它不是语言所支持的范例(只支持三个)。这就是我们为什么要加强C++0X的重要原因,因为它的目标是去除C++中长期存在的附属复杂性,使所有的诀窍变得融合(这种东西数量绝对很大;你可以参看有关C++的书籍或是C++根库,你就会明白我在说什么了),这样我们才能清晰、直接地表达我们的想法

结论

C++很难,难于正确使用。所以当你决定要用它的时候,一定要小心谨慎,一定要清楚你处在什么位置,你真正想要什么。下面是一个简单的导引:

我们需要高效吗?
如果需要,那么

在我们的代码中需要抽象吗(这个问题一定要慎重考虑,因为很难估计使用C++的高水平特性所带来的好处是否超过了正确使用它们的风险;正确的答案取决于你的编程水平训练的有多好,你遵循什么编码标准,以及这种标准加强的有多好,等)?
如果需要,那么就使用C++,否则,

我们需要C++类库来减少我们的工作量吗?
如果需要,那么就使用C++,但同时要谨记你在做什么——如果你的代码并不真的需要所有梦幻抽象,那就不要勉强使用它们;不要仅仅因为你写的代码是.cpp,你使用了C++编译器,就使用类或是模板

否则,就使用C++,但是你可能会怀疑为什么不用C++的C编码核心。同样的理由:人们很容易被稀奇古怪的语言特性所迷惑,即使他们真的不知道这些特性对他们是否有帮助——我可以不厌其烦地告诉你,我写过一串类,只是为了找出“这些类到底是什么鬼东西”。所以,如果你能坚持C核心或是带有部分C++的C核心,并且保持事情简单(KISS);或者如果你的代码需要从C移植到C++,那么就使用C++吧!但是一定要小心。另一方面,如果你的代码既不需要高性能特性,也不需要C++类库,因为你要做的事情很简单,以至于你甚至不需要像是containers或是strings这样方便的组件;或者你认为你的项目中使用C++能给你带来的好处不足以值得你冒险;或者只是因为你没有足够能正确使用C++的人员,那么你应该还是坚持用C。

最主要的:保持事情简单(KISS)(但是要记住这种简单可以通过使用高水平类库来达到);必要的时候(即使是必要,也要少用;遵循好的设计原理,养成好的习惯)使用抽象。


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值