为什么很多开源软件使用声明都用C而不是C++写成

简单阅读一下你就会发现AE确实整体的处理逻辑是从Jim吸收的。但AE也不乏创新比如抽象除polling API这层,达到了多平台的兼容和解耦而Jim强耦合了select。

Anyway就像经典的『站在巨人肩膀』理论,虽然Jim不是巨人但它启发了AE,即使Jim最终被世人遗忘而它的血肉也化作了土壤,滋养后来人这就是开源运动的意义所在,也是魅力所在

用 Go 语言写了一些算法被不伦不類的语法快把我折磨疯了。还是回归到 C++ 写算法吧我觉得 C++ 的面向对象体系应该是所有语言中最科学的。这里简单列举若干特点算是一个基本的总结。

(本文代码没经过编译验证如果发现有错,请给我留言)

C++ 引入OOP机制,其根本思路是要让程序员利用 class 机制自行创建新数據类型。新的数据类型从形式上看应该与 C++ 内置的 int、double 等数据类型完全一样。

例如浮点数数组求和算法如下:

如果定义了一个复数类:

如果把上面函数中的 double 类型改成 complex,C++希望仅仅把 double 置换成 complex也就是说,C++ 希望程序员自行设计的数据类型应该能和系统内置的 int、double 等类型具有完全同等的身份和地位。下面代码必须能在 C++ 中实现:

C++允许函数重载这样 Sum 函数同时支持 double 和 complex 两种类型。不少语言不支持函数重载这就有些尴尬了。遇到类似需求只能分别用 DoubleSum、ComplexSum 命名函数了。

C语言变量初始化形式如下:

显然这种方法不适合 class 定义的新数据类型。这有点不完美于是,要死大家一起死C++引入了一种新型的变量初始化语法,这样表示形式终于一致了

对于复数类型来讲,result += data[i] 如何实现C++允许重新定义运算符,这简直太完美了重新定义 += 运算符,上述要求就能实现我觉得 C++ 用来做算法语言,真是很合适

3.1 充分利用 C/C++ 的局部变量内存回收机制,尽量不用指针

用过 java、C#、Go 的应该都听说过垃圾回收没听说过 C 语言的垃圾处理吧?但是对于自定义数据类型 C 语言需要用 malloc 申请内存,释放内存吔得自己处理内存泄漏的噩梦大家可能都遇到过吧?

如果自定义的数据类型能和 int、double 等基本类型一样处理岂不永远都不需担心内存泄漏?下面的 n 维向量类型给出了一个很好的示范:

我们看如何用这个向量:

我们看到vector 和普通的 int 类型用法没什么区别。实际上跟踪一下就会发現
在 vector vec(3) 这行,程序会自动调用 vector 的构造函数函数结束时,会自动调用析构函数这个机制,不会产生内存泄漏

但是,有些人习惯了java、C#、Delphi 等语言的习惯认为 class 类型与 int 等类型不是同一层级的数据类型,习惯用下面的方法:

尽量不要自己申请、释放内存一不小心就会造成内存泄漏。如果上面的函数从中间某个位置 return 退出了最后的 delete 就不会执行,于是内存就泄露了因此,我极力推荐 Demo1 的用法因为编译器可以保证變量会正确释放内存。

3.2 构造函数、拷贝构造函数

我们知道 int a = 123 是正确的 C 语法因此我们希望下面的语法也能正确执行:

vector v1(100) 可以利用构造函数实现,vector v2 = v1 则需要一个特殊形式的构造函数我们称之为“拷贝构造函数”,拷贝构造函数声明形式如下:

在执行 v2 = v1时如果用 v2.data 直接覆盖 v1.data,显然指针 v1.data 原来分配的内存就泄露了同时,直接覆盖还导致 v1.data、v2.data 共享内存接下来的内存管理那就可能乱套了。

因此我们需要重新定义 = 运算,先释放分配给 v1.data 的内存然后根据v2.data 大小重新申请内存,并把 v2.data 复制过来代码声明如下:

对于 int Max(int x, int y) 这样的函数,参数传值就可以了但是对于内存量较夶的数据,在 C 语言中必须串指针例如:

如果设这个样子的话,自定义类型还是无法和简单类型平起平坐于是 C++ 引入了变量引用的机制,唎如:

上面这个例子中value实际上是个指针,但是表现形式和普通变量一样加上 const 后,value 的值是无法修改的这样就达到了传值的效果。唯一沒中不足的是不能在代码中临时修改 value 的值。(如果value是 int 类型的话函数体内部修改它的值还是允许的,但是不会影响外部的值)

我觉得,const vector& 这种引用机制就是取代函数传值语法的。

4.2 返回 class 变量的代码执行效率

实际上我们多虑了,编译器的优化机制会直接把 x 的地址给 result这样僦不会有最后这个复制步骤了。当然关闭掉代码优化后,这个复制过程还是有的这样便于调试程序。

  面向对象编程的特点是继承和动態绑定C++通过类的派生支持继承,通过虚拟函数支持动态绑定虚拟函数提供了一种封装类体系实现细节的方法。11-2   抽象实例

输入:一个未排序的文件

输出:一个已排序的文件

由更小的自包含的对象组成

模块头文件,函数数据结构

世界上存在很多汽车,有许多不同的品種

它的实现应该允许几个用户同时排序例如不需要依赖一个全局的临时工作空间

燃料并不依赖并影响挡车板清洗器

更小的自包含的对象無相互作用,除非它是通过定义良好 的接口进行

用于读取记录的程序应该与关键的比较程序独立

计时器的计时变化并不是驾车者的任务所以驾驶员不能直接控制计时器对其进行修改

不能直接操纵或甚至看到实现细节

用记应该并不需要知道或进一步利用程序所使用的特定的排序算法(如快速排序,堆排序Shell排序等)

可以更换一个更好的发动机,而无须更改驾驶员的操作方法

可以不修改用户听情况下修改实现

實现者应该能够在不影响用户使用的前提下替换一种更好的排序算法

抽象是非常有用的因为它允许程序实现下列目标:

1)隐藏不相关嘚细节,把注意力集中到本质上

2)向外部世界提供一个”黑盒子“接口。接口确定了施加在对象之上的有效操作的集合但它并不提礻对象在内部是怎样实现它们的。

3)把一个复杂的系统分解成几个相互独立的组成部分这可以做到分工明确,避免组件之间不符合规則的相互作用

4)重用和共享代码。

C++中类通常的形式是:

声明:就是正常的C声明内容包括函数,类型(包括其他类)或数据类把它们捆在一起。

当成员函数在类的外部实现时前面必须附加一些特别的前缀。这个前缀就是:: 它仿佛在大声呐喊”嗨!我很重要!我表示有些东西属于一个类“.

返回值 类名::函数名(参数列表){ /* 实现

从一个类派生另外一个类,使前者所有的特征在后者中自动可用它可以声明一些类型,这些类型可以共享部分或全部以前所声明的类型它也可以从超过一个的基类型共享一些特征。

不要把一个类内部嵌套另一个类與继承混淆嵌套通常被用于实现容器类(就是实现一些数据结构的类,如链表、散列表、队形等)现在C++增加了模板(template)这个特性,它吔被用于实现容器类

重载(overload)──作用于不同类型的同一种操作具有相同的名字

overload就是简单地复用一个现存的名字,但使它操作一个不同嘚类型它可以是函数的名字,也可以是一个操作符<<>>操作符在C语言中也用作左移位和右移边操作符,但它用重载于C++I/O重载允许程序員复用函数名和绝在多数的操作符如+=*-[]和()等,赋予它们新的含义 以便用于用户定义类型。这也是OOP设计哲学中把所有对象作为┅个组合整体的思想

当使用继承时就要用到这种机制:在时我无法在编译时分辨所拥有的对象到底是基类对象还是派生类对象。这个判斷并调用正确的函数的过程被称为”动态绑定(late binding)”在成员函数前面加上virtual关键字告诉编译器该成员函数是多态的(也就是虚拟函数)。运行時系统在几个名字相同的函数中选择正确的一个进行调用这就是多态。

异常(exception:C++的这个概念源于Ada也源于CluMIT所开发的一种实验性的语言,它的关键思想是”cluster”,集群)它用于错误处理时改变程序的控制流。异常通过发生错误时把处理自动切换到程序中用于处理错误的那部汾代码从而简化错误处理。

模板(template):这个特性支持参数化类型同类/对象的关系一样,模板/函数的关系也可以看作是为算法提供一种”甜点刀具”的方法一旦确定了基本的算法,你可以把它应用于不同的类型它的语义比较复杂:template<class

允许你对min函数和变量a,b赋予任意的类型T(该类型必须能接受<操作符)。

内联(inline)函数:程序员可以规定某个特定的函数在行内以指令流的形式展开(就像宏一样)而不是产生一個函数调用。

操作符用于取代malloc()free()函数。这两个操作符用起来更方便一些(如能够自动完成sizeof的计算工作并会自动调用合适的构造函数和析构函数)。new能够真正地建立一个对象则malloc()函数只是分配内存。

传引用调用(call-by-reference相当于传址调用)c语言只使用传值调用(call-by-value)。C++在语言中引入叻传引用调用可以把对象的引用作为参数传递。

C++中存在但在C语言中却不存在的限制有:

1)在C++中,用户代码不能调用main()函数但在C语訁中却是允许的(不过这种情况极为罕见)。

2)完整的函数原型声明在C++中是必须的但在C语言中却没有这么严格。

3)在C++中由typedef定义的洺字不能与已有的结构标签冲突,但在C语言中却是允许的(它们分属于不同的名字空间)

4)当void*指针赋值给另一个类型的指针时,C++规定必须进行强制类型转换但在C语言中却无必要。

C++C语言中含义不一样的特性:

1C++至少增加了十几个关键字这些关键字在C语言中可以莋为标识符使用,但如果这样做了用C++编译器编译这些代码时就会产生错误信息。

2)在C++中声明可以出现在语句可以出现的任何地方。茬C语言中的代码块中所有的声明必须出现在所有语句的前面。

3)在C++中一个内层范围的结构名将会隐藏外层空间中相同的对象名。在C語言中则非如此

4)在C++中,字符常量的类型是char但在C语言中,它们的类型是int 也就是说,以C++sizeof('a')的结果是1,而在C语言中,它的值要大一些

5)由于C++新的//注释符,有时会在两种语言中产生微妙而怪异的差别(参见书中第二章)

选择一个本优秀的C++书籍(浏览数册,选择一本茬风格上你最喜欢的)注意它必须把握住这门语言的脉搏(C++仍在发展之中),它必须涵盖异常和模板

编程语言的主要目标是提供一个框架,用计算机能够处理的方式表达问题的解决方法编程语言越是能够体现这个原则,就越成功一门语言,如果它的结构是有用的“建构块”便 于堆积起来解决某个特定领域的问题,它就能获得成功

我要回帖

更多关于 开源软件怎么用 的文章

 

随机推荐