我仍然觉得 C++ 提供了一些无法被击败的东西。我无意在这里发起一场激烈的战争,如果你对不喜欢 C++ 有强烈的意见,请不要在这里发泄。我很想听听 C++ 大师们为什么坚持使用它。
我对 C++ 鲜为人知或未充分利用的方面特别感兴趣。
编辑:人们,请至少粗略阅读其他回复,以确保您没有重复已经说过的话,如果您同意其他人所说的话,请点赞!
RAII/确定性最终确定。不,当您处理稀缺的共享资源时,垃圾收集并没有那么好。
不受限制地访问操作系统 API。
我一直使用 C++,因为对于需要结合效率和复杂性的应用程序来说,它仍然是性能最高的通用语言。例如,我为测量行业的手持设备编写了实时表面建模软件。鉴于资源有限,Java、C# 等...只是不提供必要的性能特征,而 C 等较低级别的语言在抽象特征较弱的情况下开发速度要慢得多。C++ 开发人员可用的抽象级别范围是巨大的,在一个极端情况下,我可以重载算术运算符,这样我就可以说像MaterialVolume = DesignSurface - GroundSurface同时运行多个不同的堆来最有效地管理特定设备上我的应用程序的内存。将其与用于解决几乎任何常见问题的大量免费资源相结合,您就拥有了一种强大的开发语言。
C++ 仍然是大多数领域中大多数问题的最佳开发解决方案吗?可能不会,尽管在紧要关头它仍然可以用于大多数人。它仍然是高效开发高性能应用程序的最佳解决方案吗?恕我直言,毫无疑问。
射中自己的脚。
没有其他语言能提供如此丰富的工具。指针、多重继承、模板、运算符重载和预处理器。
一种非常强大的语言,也为足部拍摄提供了丰富的机会。
编辑:如果我蹩脚的幽默尝试冒犯了一些人,我深表歉意。我认为 C++ 是我曾经使用过的最强大的语言——在需要时可以在汇编语言级别进行编码,并在需要时进行高级抽象。自 90 年代初以来,C++ 一直是我的主要语言。
我的回答是基于多年射击自己的脚的经验。至少 C++ 允许我优雅地做到这一点。
确定性对象破坏导致一些宏伟的设计模式。例如,虽然 RAII 不像垃圾收集那样通用,但它带来了一些令人印象深刻的功能,而这些功能是 GC 无法获得的。
C++ 的独特之处还在于它具有图灵完备的预处理器。这允许您更喜欢(与 defer 相反)许多代码任务在编译时间而不是运行时间。例如,在实际代码中,您可能有一个 assert() 语句来测试从未发生过的情况。现实情况是,它迟早会发生......并且发生在凌晨 3:00,当你在度假时。C++ 预处理器断言在编译时执行相同的测试。当您坐在电脑前观看代码构建时,编译时断言在上午 8:00 到下午 5:00 之间失败;当您在夏威夷睡着时,运行时断言在凌晨 3:00 失败。在那里很容易看到胜利。
在大多数语言中,策略模式是在运行时完成的,并在类型不匹配的情况下抛出异常。在 C++ 中,策略可以在编译时通过预处理器工具完成,并且可以保证类型安全。
编写内联汇编(MMX、SSE 等)。
确定性对象破坏。即真正的析构函数。使管理稀缺资源更容易。允许 RAII。
更轻松地访问结构化二进制数据。将内存区域转换为结构比解析它并将每个值复制到结构中更容易。
多重继承。并非所有事情都可以通过接口完成。有时您也想继承实际功能。
我想我只是要赞扬 C++ 能够使用模板来捕获表达式并在需要时懒惰地执行它。对于那些不知道这是什么的人,这里有一个例子。
模板混合提供了我在其他地方没有见过的重用。使用它们,您可以构建一个具有许多行为的大型对象,就好像您是亲手编写的一样。但是其功能的所有这些小方面都可以重用,它对于实现部分接口(或整个事物)特别有用,您正在实现许多接口。生成的对象快如闪电,因为它都是内联的。
在许多情况下速度可能并不重要,但是当您编写组件软件时,用户可能会以意想不到的复杂方式组合组件来做事,内联和 C++ 的速度似乎允许创建更复杂的结构。
在需要时对内存布局、对齐和访问进行绝对控制。如果您足够小心,您可以编写一些对缓存非常友好的程序。对于多处理器程序,您还可以从缓存一致性机制中消除很多减速。
(好吧,您可以在 C、汇编和可能的 Fortran 中执行此操作。但是 C++ 允许您在更高级别编写程序的其余部分。)
这可能不是一个流行的答案,但我认为 C++ 的不同之处在于它的编译时功能,例如模板和#define。您可以使用这些功能对您的程序进行各种文本操作,其中大部分已在后来的语言中以简单的名义被放弃。对我来说,这比任何在 C++ 中更容易或更快的低级位摆弄更重要。
例如,C# 没有真正的宏工具。您不能将另一个文件直接#include 到源代码中,或者使用#define 将程序作为文本进行操作。想想任何时候你不得不机械地输入重复的代码,你知道有更好的方法。您甚至可能已经编写了一个程序来为您生成代码。好吧,C++ 预处理器自动化了所有这些事情。
与 C++ 模板相比,C# 中的“泛型”工具同样受到限制。C++ 允许您盲目地将点运算符应用于模板类型 T,调用(例如)可能不存在的方法,并且仅在模板实际应用于特定类时才应用正确性检查。发生这种情况时,如果您对 T 所做的所有假设实际上都成立,那么您的代码将编译。C# 不允许这样做...类型“T”基本上必须作为对象处理,即仅使用可用于所有操作的最低公分母(赋值、GetHashCode()、Equals())。
C# 以简单的名义取消了预处理器和真正的泛型。不幸的是,当我使用 C# 时,我发现自己正在寻找这些 C++ 结构的替代品,这些结构不可避免地比 C++ 方法更臃肿和分层。例如,我见过程序员以几种臃肿的方式解决#include 的缺失问题:动态链接到外部程序集、在多个位置重新定义常量(每个项目一个文件)或从数据库中选择常量等。
正如《辛普森一家》的 Crabapple 女士曾经说过的那样,这“太蹩脚了,米尔豪斯”。
在计算机科学方面,C++ 的这些编译时特性支持诸如按名称调用参数传递之类的事情,众所周知,它比按值调用和按引用调用更强大。
同样,这可能不是流行的答案——例如,任何介绍性 C++ 文本都会警告您不要使用#define。但是多年来一直使用多种语言,并考虑到所有这些背后的理论,我认为很多人给出了不好的建议。在被称为“IT”的稀释子领域中似乎尤其如此。
C# 和 Java 强制您将“main()”函数放在一个类中。我觉得这很奇怪,因为它稀释了类的含义。
对我来说,类是问题域中的一类对象。程序不是这样的对象。所以你的程序中不应该有一个名为“程序”的类。这相当于使用符号来表示自己的数学证明——证明——以及表示数学对象的符号。这将是奇怪和不一致的。
幸运的是,与 C# 和 Java 不同,C++ 允许使用全局函数。这让您的 main() 函数存在于外部。因此,C++ 提供了一个更简单、更一致并且可能更真实的面向对象习语的实现。因此,这是 C++ 可以做的一件事,但 C# 和 Java 不能。
以最小的开销跨进程传递 POD 结构。换句话说,它使我们能够轻松处理二进制数据块。
我认为运算符重载是一个非常好的功能。当然,它可能会被滥用(就像在 Boost lambda 中一样)。
严格控制系统资源(尤其是内存),同时可选地提供强大的抽象机制。在这方面,我所知道的唯一可以接近 C++ 的语言是 Ada。
C++ 提供了对内存的完全控制,因此使程序执行流程更加可预测。您不仅可以准确地说出内存分配和释放的时间,还可以定义自己的堆,拥有多个用于不同目的的堆,并准确说出内存数据分配到的位置。这在嵌入式/实时系统(如游戏机、手机、mp3 播放器等)上编程时经常有用,其中:
AFAIK、C 和 C++ 是做这种事情的唯一明智选择。
老实说,如果您愿意编写足够多的代码,您几乎可以做任何事情。
所以要回答你的问题,不,没有什么是你不能用 C++ 做的另一种语言做的。只是你有多少耐心,你愿意付出漫长的不眠之夜来让它发挥作用吗?
C++ 包装器使某些事情变得容易(因为它们可以读取头文件),例如 Office 开发。但同样,这是因为有人写了很多代码在 RCW 或“运行时可调用包装器”中为你“包装”它
编辑:你也意识到这是一个加载的问题。