热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

强大不代表完美——C++几个不方便的地方。

说明:本文章纯属个人观点,不保证绝对正确,欢迎大家批评和指正,同时我自己也会对本文不断的更新和完善。引言:本文自工作以来使用过C++、Java、Pytho

说明:本文章纯属个人观点,不保证绝对正确,欢迎大家批评和指正,同时我自己也会对本文不断的更新和完善。


引言:
本文自工作以来使用过C++、Java、Python、Groovy、Objective C、Lisp,我最初学的就C++的,当时对她情有独钟,灵活和强大充分体现了她的智慧,随着你对她理解的深入,你会发现随便一段代码会有很大的优化余地,以致于大牛和小菜写的代码有很大的区别,举个十常简单的例子,串拷贝大家都熟悉吧(至少是一道常考的面试题,我也经常拿此考考应届生 大笑):

数据结构书上的最终版是这样的(注意:本文所有代码都不是商用版本,为了简洁,没注意风格的良好性):

void strcpy(char* des, const *char src) 
{
    while(*des++ = *src++);
}
最原始版本是这样写的:
void strcpy(char* des, const char* src) 
{
    while(*src != '\0')
    {
        *des = *src
        des++
        src++;
    }
}
当然,中间还是许多进化版本,不是一步跳过来的,具体请参考谭浩强的《数据结构》,这里只是说明同样的功能,可以充分利用C++语言灵活语法写出非常精炼的代码,这里利用到的语言特性有:操作符优先级、结束符'\0'等价于0或NULL、非0即为真。这只是个简单的例子,如果应用类指针、泛型、虚继承等特性,就可以在大项目中做出很多优化,使得代码精炼且高效。

(题外话:有很多书和文章出于易读性原则,不鼓励第一种风格,我觉得没那么糟糕,如果是常用的,人人都熟练某一段,这样写就相当于单词缩写,就好比设计模式一样是一种共同语言,你一说关键字,人家立刻就明白这一整块代码)

总之,C++给我的感觉就是:只有想不到,没有做不到。

但是当我学过其它语言之后,发现C++并不是我想像中的完美,每种语言都有自己独到的智慧,虽然并不是每一种我都熟悉,但她们的设计思想让我受益匪浅。如果说C++灵活,那世上还有另一种灵活,经过几年工作的提炼,我发现C++有这些不方便之处。

以下是我当前想到的:

.头文件

这是我发现的每一个不方便的地方,这件事由来还挺曲折离奇的,我学的第二种语言是Java,当时是为了开发ZTE第一个Android的机顶盒,当时那里只有一两个人懂Android,而且马上就要离职了,所以就只有赶鸭子上架了,叫我去学Java,开发Android应用,我当时还是唯C++独尊,带着鄙视Java的情绪去学习Java,第一天,写了个HelloWorld,发现Java竟然没有头文件,当时心里就想这是什么扯淡语言,头文件都没有,那我怎么提供接口给别人还不用暴露我的实现。但后来,随着学习的深入,发现Java根本就不需要头文件,它的接口信息都包含在.class里了,甚至还会包含接口的注释。

不用头文件,编程时显示要方便一点,改函数名的的时候不用改两个文件了,因为那显然有冗余的工作量,即然是冗余就应该让机器去做,不要耽误人的时间。所以我觉得可以在C编译成的*.o文件前面部分放入接口信息,这样别人引用可以像Java或Objective C或Python这样import了。

.函数必须先申明再调用

【注意这里说的不是变量的先申明再使用】这个规矩相当难受,其实只要编译器搜索一遍本文件,就可以找出写在后面的函数了,这样只是耽误一点编译时间,即不会影响运行效率,还可以使人少写些代码并减少人放错的概率,何乐而不为呢?

.成员变量申明时不能初始化

我想多数人学C++时,都会自然而然的认为成员变量申明的时候就可以给他赋个初始值,像这样:

// file1.cpp
class Foo
{
    int bar = 0; //wrong in C++, but legal in Java
}

在C++是允许这样的,按照官方的说法,申明文件是属于类的而不是属于对象的,不管他怎么说,Java也可以申明时定义,我觉得这样很方便,也符合人的思考习惯,其实你可以当成初始化值来理解,无论如何,这条规定来了不便。

.泛型语法不够简洁

同是泛型,Java的语法就比C++要简洁的多,一个单一泛型方法在C++中是这样表示:

template 
int compare(const T &v1, const T &v2)
{
    // ...
}
而在Java中是这样:
static  int compare(T v1, T v2) {
    // ...
}
(用static是因为Java没有单独的函数,所以方法必须写进类,static方法更C++的函数最像),一个泛型类在C++中这样的:
template  
class Foo 
{
public:
    void bar(T arg1);
    // ...
};
而在Java中是这样的:
class Foo {
     public void bar(T arg1){};
}
显然,C++多了个关键字template和typename,而Java只要一对尖括号就可以了,更易记忆,更简洁,写代码也方便。有可能因为Java来源于C++,Java创造者意识到这一点,才改进的。所以理论上C++也可以支持这样的语法,应该改一下编译器就可以了。

.标准库不强大

相比Java的标准库,C++的STL实在是太薄弱了,就几个容器类,什么网络编程,加密算法都没有,全部都得到网上找开源的库,同时使得人人都要造车轮,大大的加长了开发周期,更延缓了C++自身的发展。

.API注释
Java的.class文件里已包含了注释,使得在集成开发环境里,可以边编程边查看API说明,如下图:


我觉得C++也可以把注释打包到.o和.so文件里,这样别人用你的库的时候就不会找你要文档(你还很有可能没写)或问题你怎么用了,当然这个功能应该可配置,以满足一些担心库被泄漏的用户。

.做Linux开发没有一个好用的集成开发环境

这个虽然跟C++语言本身没有多大联系,但这可能是做C++的工程师的一块痛处,这条可能会有很多人反对,有人会觉得可以通过配置vim或emacs(这个东西不一定好使,却是一个很好的“装逼”利器,我也研究过,的确很有面子,特别是在新手MM面前)来使用强大的功能,配置复杂不说(有一个哥们用的emacs有3000行的配置文件,不过那人是兴趣原因),也不是很好用,显然没有window上的VS和Eclipse开发Java那么智能,用Eclipse开发Java从来都没用担心编译问题,在C++上可能只通过边写边手动频繁的办法来减少编译问题带来的痛苦。还有人会觉得集成开发环境不好,会使得程序员对编译细节和程序的生成过程全然不知,这个我以前也这么认为,还专门学习研究编译和可执行文件,还绞尽脑汁看过龙书(Alfred V. Aho写的编译原理),但后来发现没什么用处,如何不是写编译器,那些知识很难派上用场,久而久之,我都忘了。所以我认为,程序员应该有更多的时间去思考软件的设计和架构,而不是那些简单又繁琐的编译工作,更不应该每天去重复做这些事情,应尽可能让机器去做。比如说自动完成功能可以大大提高输入效率;自动显示API注释功能使得不需要先查文档才知道使用;写注释也很方便,只需在方法前输入“/**”再输入回车,就会自动完成API注释结构,包括参数名,如下图:


边写边后台编译的使得再不用担心编译错误,还有错误提示并给出建议方案,如下图:


函数未返回值给出的建议,如果你点击第一个选项,就会自动帮你加上一行"return 0;",下图到达不了的代码两个示例,有提示

   

还有重构功能,在Eclipse中重构很简单,比如你改一个函数名,他会自动帮你更改所有调用处,包括其它的工程,这个功能苹果家的XCode也有,你用C++估计得使用一番Ctrl+F、Ctrl+C、Ctrl+V了,如果第二天又想改回来,你又得痛苦了。除此之后还有其它很多强大的功能,在此就不一一列举了。

.匈牙利命名法

这个好像也跟C++关系不大,不过实际上也是由于IDE不强大造成的,我想有人希望看到这种命名法写的代码,没人喜欢写这种命名法的代码,特别是有时想改某个变量的类型时,如int型改char型,这个时候你就得一个个改了,其实本质是要看到类型信息,看看强大的IDE是怎么做的:


在鼠标悬停的时候自动显示了,类型信息根本就不要在变量名上体现,我还听说这种命名法是微软发明,我在想他微软为何不直接改一下VS的代码增加这个功能而去增加他千千万万的员工的工作量呢,更想不通的是为何还流行了这么多年,难道没人发现这个问题吗,还是我想错啦。

说明:本文章纯属个人观点,不保证绝对正确,欢迎大家批评和指正,同时我自己也会对本文不断的更新和完善。


推荐阅读
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
author-avatar
wwwmanbj_796_897
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有