it-swarm.cn

C与C ++有何不同?

许多人说过C++是与C完全不同的语言,但是Bjarne本人也曾说过C++是从C扩展而来的语言,因此++来自。那么,为什么每个人都在说C和C++是完全不同的语言呢?除了C++的扩展功能外,C与C++有何不同?

21
Joshua Partogi

在1980年代,当C++开发才刚刚开始时,C++几乎是C的一个适当的超集。这就是一切的开始。
然而,尽管人们一直认为语言之间的兼容性很重要,但随着时间的流逝,C和C++都在发展并且彼此脱节。

此外,C和C++之间的技术差异使得这些语言中的典型习语变得更加复杂。

这是人们说“没有C/C++这样的语言”或“ C和C++是两种不同的语言”之类的驱动因素。尽管可以编写C和C++编译器都可接受的程序,但是通常认为该代码既不是优质C代码的示例,也不是优质C++代码的示例。

18
Bart van Ingen Schenau

Stroustrup自己在 他的常见问题解答 中回答了这个问题:

C++是C的直接后代,几乎保留了所有C作为子集。 C++比C提供更强大的类型检查,并且直接支持比C更广泛的编程样式。C++是“更好的C”,从某种意义上说,它支持使用C完成的编程样式,具有更好的类型检查和更多的符号支持(不损失)。效率)。从同样的意义上说,ANSI C比K&R C更好。C++支持数据抽象,面向对象的编程和通用编程。

它支持使C++与C“完全不同”的面向对象编程和通用编程。您can几乎可以编写纯C,然后使用C++编译器(只要您负责更严格的类型检查)。但是然后您仍然在编写C-您不是在编写C++。

如果您正在编写C++,那么您将利用它的面向对象和模板功能,这与在C语言中所看到的完全不同。

20
Dean Harding

简而言之,在C中被认为是惯用的在C++中绝对不是惯用的。

实际上,由于人们使用C和C++的方式不同,因此它们是不同的语言。 C的目标是极简主义,其中C++是一种非常复杂的语言,具有lot特征。

还有一些实际的区别:几乎可以从任何一种语言调用C,并且经常定义平台的ABI,而从其他库很难使用C++。大多数语言甚至都使用C++(例如Java)实现的语言都具有C的FFI或接口。

13
David Cournapeau

除了显而易见的事实,即C++支持面向对象的编程外,我想您在这里也能找到答案: http://zh.wikipedia.org/wiki/Compatibility_of_C_and_C++

该文章包含一些代码示例,这些示例显示了在C中可以但在C++中没有问题的东西。例如:

int *j = malloc(sizeof(int) * 5); /* Implicit conversion from void* to int* */

将C程序移植到C++通常很简单,并且主要包括修复编译错误(添加强制转换,新关键字等)。

4
Martin Wickman

C++不仅为C增加了新功能,而且还增加了新概念和新用法。尽管C++和C紧密相关,但事实是,要有效地用一种语言编写,必须以该语言的风格进行思考。即使是最好的C代码也无法利用C++的不同优势和习惯用法,因此bad C++代码比实际更可能。

2
Jon Purdy

“扩展功能”使您听起来像在C++中一样,它们添加了可变参数宏之类的东西,仅此而已。 C++中的“扩展功能”是该语言的完全检修,并且完全取代了最佳C实践,因为新的C++功能比原始的C功能好得多,以至于原始的C功能完全且在绝大多数情况下完全多余。暗示C++仅扩展了C,这表明现代战车出于发动战争的目的而扩展了一把刀。

2
DeadMG

不同之处在于,在C语言中,您以程序方式进行思考,而在C++语言中,则以面向对象的方式进行思考。语言非常相似,但方法却大不相同。

1
Ant

虽然C++在语法上可以是C的超集-即C++程序的任何构造都可以由C++编译器进行编译。

但是,您几乎永远不会像使用C程序那样编写C++程序。该列表可以是无止境的,也可以是有人应该做更多研究以将其作为详尽的报告。但是,我只提出一些关键区别的建议。

本篇文章的重点是C++具有以下功能,即使可以编译等效的C语言,优秀的C++程序员也必须将其用作编程最佳实践。

如何在C++中通过C实现

  1. 类和继承。这是允许系统化的面向对象的最重要的区别,这使得编程表达非常强大。我想-这一点不需要更好的解释。如果您使用C++-几乎总是这样,那么最好使用类。

  2. 私有化-类,甚至结构都有私有成员。这使得类的封装成为可能。 C语言中的等效项是通过将对象作为void *类型转换为应用程序,从而使应用程序无法访问内部变量。但是,在C++中,可以具有公共类和私有类的元素。

  3. 通过引用。 C++允许基于引用进行修改,为此需要传递指针。引用传递使代码保持非常干净,从而更安全地防止指针危险。您也可以通过C样式指针,并且可以工作-但是,如果您使用的是C++,则只要

  4. 新&删除与malloc和免费。 new()和delete()语句不仅分配和取消分配内存,还允许代码作为分解器的一部分执行,以在链中调用。如果您使用的是C++,则实际上不宜使用malloc和free。

  5. IO类型和操作符重载如果操作得当,操作符重载可使代码可读或更直观。与<<和>> io运算符相同。使用此方法的C方法是使用函数指针-但这很麻烦,并且仅适用于高级程序员。

  6. 使用“字符串”。来自C的char *随处可见。因此,C和C++几乎相同。但是,如果您使用的是C++,则使用String类总是更好(更安全),这使您免于数组运行的危险,这几乎是所有事情。

我在C++中仍然不会喜欢的功能 1.模板-虽然我在许多代码中都不使用繁重的模板-事实证明它对库非常强大。在C语言中几乎没有它。

  1. 智能指针-是的,它们非常聪明!就像大多数聪明的东西一样-它们开始时很好,后来变得凌乱!我不太喜欢用

我喜欢C的东西而C++错过的东西

  1. 使用函数指针的多态算法。在C中,当您运行复杂的算法时-有时您可以使用一组函数指针。这以强大的方式实现了真正的多态。当您使用C++时,您可以使用函数指针[〜#〜] [〜#〜],但这很糟糕。您应该只使用方法-否则会变得凌乱。 C++类中多态的唯一形式是函数和运算符重载,但这是非常有限的。

  2. 简单线程。当创建线程时是pthreads-它非常简单且易于管理。当您需要创建应该是类的“私有”线程(以便它们可以访问私有成员)时,它就变成了。有boost类型的框架-但在基本的C++中没有。

地盘.

0
Dipan Mehta

某些语言功能,即使它们是附加功能,也可以改变实际上需要使用该语言的整个方式。作为一个示例,请考虑这种情况:

lock_mutex(&mutex);

// call some functions
...

unlock_mutex(&mutex);

如果上面的代码涉及调用用C++实现的函数,那么我们可能会遇到麻烦,因为这些函数调用中的任何一个都可能抛出,并且我们永远都不会在那些特殊的路径中解锁互斥量。

析构函数不再具有便利性,可以帮助程序员避免在那一刻忘记释放/释放资源。 RAII成为一项实际要求,因为预见可能会在不平凡的示例中抛出的每一行代码在人类上都是不可行的(更不用说这些行现在可能不会抛出,但以后可能会进行更改)。再举一个例子:

void f(const Foo* f1)
{
    Foo f2;
    memcpy(&f2, f1, sizeof f2);
    ...
}

这样的代码虽然在C语言中通常是无害的,但就像C++中的地狱般的混乱一样,因为memcpy推翻了这些对象的位和字节,并绕开了诸如复制构造函数之类的事情。诸如memsetreallocmemcpy等功能,而C开发人员中的日常工具习惯于以相当类似的方式查看内存中的位和字节,与更复杂和更丰富的C++类型系统不协调。 C++鼓励使用更加抽象的用户定义类型视图。

因此,这些类型的事物不再允许C++,任何希望正确使用它的人都将其视为C的“超集”。这些语言需要非常不同的思维方式,纪律和思维方式,才能最有效地使用C++。 。

我并不是在各个方面都认为C++更好的阵营,实际上出于某些原因,我最喜欢的第三方库大多数是C库。我不知道为什么会这样,但是C库在本质上往往更趋于极简(也许是因为缺少这种丰富的类型系统使开发人员更加专注于提供所需的最小功能,而无需构建一些大层次的抽象集),虽然我经常最终只是将C++包装器放在它们周围,以简化和调整其用途以达到我的目的,但是即使这样做,极简主义也比我更合适。我真的很喜欢极简主义,因为它是图书馆的吸引人之处,它吸引了一些额外的时间来寻求这些品质,并且也许C倾向于鼓励这样做,但前提是仅凭这样的事实,即如此庞大,分层和抽象的代码将是在C中开发真正的PITA。

我确实更偏爱C++,但是实际上我经常需要使用C API以获得最大的二进制兼容性(以及FFI),尽管我尽管使用C作为标头也经常使用C++实现它们。但是有时候,当您真正进入底层时,例如内存分配器或非常低层的数据结构(我敢肯定,从事嵌入式编程的人中还有更多的例子),有时对您有所帮助能够假定您正在使用的类型和数据缺少某些功能,例如vtables,costructor和de析构函数,因此我们可以将它们视为位和字节以随机播放,复制,释放,重新分配。对于非常特别低级的问题,有时使用C提供的更为简单的类型系统可能会有所帮助,当然,它倾向于更快地构建等等。

澄清

在这里我想对更多有趣的评论做一个更深入的介绍(我发现这里的评论对字符数限制非常严格):

如果Foo有任何拥有的指针,则memcpy(&f2, f1, sizeof f2);在C中也是“地狱般的破坏”,甚至更糟,因为您也缺乏处理该指针的工具。

这是一个公平的观点,但是我所关注的一切主要集中在C++的类型系统以及RAII方面。在C语言中,此类x rayish字节复制memcpyqsort类型的函数造成的实际危险较小的原因之一是,上面的f1f2的销毁是明确的(如果它们甚至需要非平凡的破坏),而当析构函数进入画面时,它们变得隐含且自动化(通常对开发人员而言具有巨大的价值)。更不用说像vptrs之类的隐藏状态了,这些功能将立即结束。如果f1拥有指针,而f2在某些临时上下文中浅表复制了它们,那么如果我们不尝试第二次显式释放那些拥有的指针,那也没有问题。使用C++,编译器会自动执行此操作。

通常情况下,这在C中变得更大if,“If Foo拥有自己的指针”,因为资源管理所需的显式性通常会使某些事情通常更容易被忽略,而在C++中,我们可以使UDT不再简单地可构造/可破坏,只需将其存储为“ t可构造性/可破坏性(再次以一种通常非常有用的方式,但是如果我们很想使用memcpyrealloc之类的函数,则不是这样)。

我的主要观点不是试图争辩这种明确性的任何好处(我想说,如果有的话,它们几乎总是被随之而来的人为错误可能性增加的弊端所压倒),而只是说诸如memcpymemmoveqsortmemsetrealloc之类的函数在UDT丰富的语言中没有位置C++的特性和功能。尽管它们无论如何存在,但我认为不必说绝大多数C++开发人员会明智地避免诸如瘟疫之类的功能,而这些都是C语言中日常的功能,因此d认为,由于C类型系统更为基本,甚至是“笨拙”,因此它们在C语言中造成的问题更少。 X射线C类型并将其视为位和字节是容易出错的。在C++中这样做完全是错误的,因为此类函数与语言的非常基本的特性以及类型系统所鼓励的特性相抵触。

实际上,这实际上是C语言对我最大的吸引力,特别是在C语言与语言互操作性之间的关系方面。要使诸如C#的FFI之类的东西了解C++的成熟类型系统和语言功能,到构造函数,析构函数,异常,虚函数,函数/方法重载,运算符重载,所有各种类型的东西,要困难得多。对于C,这是一种相对笨拙的语言,它已成为相当标准的API,其方式是许多不同的语言可以直接通过FFI导入,也可以通过某些C API导出函数以所需形式间接导入(例如:Java Native Interface)。这就是我几乎只能选择使用C的地方,因为在我们的案例中,语言互操作性是一个实际的要求(尽管我经常只是用C++编写C接口背后的实现)。

但是你知道,我是一个实用主义者(或者至少我努力成为)。如果C是最肮脏和令人讨厌的,易出错的,讨厌的语言,我的一些C++发烧友都声称它是C(我算自己是C++发烧友,只是因为某种程度上它不会导致对C的仇恨;相反,这对我产生了相反的影响,使我在各自的方面和差异方面更好地体会了这两种语言),然后我希望它以一些最笨拙,漏洞最严重的形式出现在现实世界中,用C编写的不可靠的产品和库。我找不到。我喜欢Linux,喜欢Apache,Lua,zlib,我发现OpenGL可以抵抗长期变化的硬件要求(Gimp,libpng,Cairo等),因此可以容忍OpenGL。至少该语言所构成的障碍似乎并没有造成僵局我会很感兴趣地写一些很酷的库和产品,这才是我真正感兴趣的。因此,我从来没有对最激烈的语言战争如此感兴趣,只是发出了务实的呼吁并说:“嘿,让我们学习他们是如何做到的,也许还有一些很酷的课程,不是专门针对该语言的惯用本质的,因此我们可以将其恢复为正在使用的任何一种或多种语言。” :-D

0
Dragon Energy