C# 与 C++:核心是什么?
已发表: 2022-03-11在快节奏和不断发展的软件工程世界中,不同的编程语言正在争夺在行业中的一席之地。 然而,不同的语言使用不同的范式,并且往往有很长的优缺点列表,这使得它们之间的直接比较具有挑战性和不确定性。
但是,有些语言具有相似的语法和重点,因此将它们并排比较是有意义的。 在本文中,我们研究了 C++ 和 C# 之间的区别,并比较了这些多产的编程语言。
C# 和 C++ 简史
在 1970 年代,丹麦计算机科学家 Bjarne Stroustrup 撰写博士论文时,他想使用第一个面向对象的编程语言 Simula。 但事实证明 Simula 太慢了,所以 Stroustrup 决定使用 C,它曾经是——有些人会说仍然是——最快的编程语言。
在使用 Simula 之后,Stroustrup 开始开发一种基于 C 的面向对象语言,到 1985 年,C++ 向公众开放。
他决定让 C++“尽可能接近 C,但不是更接近”,这意味着采用不会成为障碍。 由于所有 C 库都可以自动使用,因此许多顶级 C 开发人员能够通过在现有知识的基础上转换到 C++。
不幸的是,与 C 与生俱来的相似性也是 C++ 的弱点之一,因为这两种语言都需要陡峭的学习曲线并且难以掌握,这使得编码对于没有经验的开发人员来说是一个挑战。
这是 Sun Microsystems 在 90 年代中期决定创建 Java 的关键原因之一。 Java 的语法类似于 C++,但它简化了语言结构并减少了意外错误的可能性。 由 James Gosling 领导的 Java 团队主要通过放弃与 C 的向后兼容性来实现这一点。
2002 年,微软发布了 C# 作为 Java 的直接竞争对手。 作为一种替代语言,C# 与 Java 共享一些语法,但具有更多功能。 自发布以来,C# 和 C++ 都得到了显着改进。
带有警告的面向对象编程语言
当 C++ 出现时,大多数编程语言都是面向过程的。
在过程式编程语言中,程序被组织成更小的单元,称为过程。 每个过程对应于稍后在更大单元中使用(调用)的一些常见操作。
在面向对象的语言中,过程围绕执行它们的对象进行分组。 对象是保持某种状态的逻辑单元。
C# 是一种完全面向对象的语言,而 C++ 是一种可以混合过程代码和面向对象代码的语言。
C# 和 C++ 之间的相似之处
两种语言都是面向对象的并且基于 C。此外,C# 基于 C++,这使得它们非常相似。 那些对任何一种语言都不流利的人很容易通过浏览代码将一种语言误认为另一种语言。
这两种语言都具有面向对象语言中常见的特征,包括:
- 封装。 代码按逻辑组组织,称为类。
- 数据隐藏。 部分数据和代码是私有的,这意味着它们只能从类中访问。
- 遗产。 共享类功能可以组织在派生类继承的公共类中,从而避免代码重复。
- 多态性。 代码能够影响基类的对象,但对于不同的派生类表现不同。
C# 和 C++ 之间的差异
C++ 的一些强大功能难以理解并且可能导致编程错误。 这些特性在 Java 中被有意省略,随后在 C# 中被省略:
- 多重继承。 派生类继承多个基类。 C# 引入了没有实现的基类,而不是这个特性。 此类类在 C# 中称为接口。
- 指针。 虽然可以在 C# 中使用指针,但必须将使用指针的代码标记为“不安全”。 这种做法是非常不鼓励的,而是使用参考。
- 精度损失。 C# 不允许隐式类型转换导致精度损失。 如果精度即将丢失,则需要显式转换。
内存管理
也许 C# 和 C++ 之间最重要的区别是内存管理。
在 C 中,动态内存(即,内存分配事先不知道)使用malloc函数分配并使用free释放。 程序员应该手动管理内存。 因此,内存泄漏是 C 代码中的常见错误。
C++ 中的内存管理得到了改进,因为内存是半自动管理的。 可以使用称为“智能指针”的对象,因此程序员不必手动释放内存。 但是,在某些边缘情况(循环引用)中,智能指针不足以防止内存泄漏。
C# 使用垃圾收集器 (GC),它会自动释放不再使用的内存。 虽然这看起来很理想,但有时 GC 使释放一个拥有除内存以外的系统资源(例如,文件句柄或 TCP 连接)的对象具有挑战性。 在这种情况下,可能会发生一种被称为“资源泄漏”的现象,程序员必须手动释放持有资源的对象。 在这些罕见的情况下,C# 中的释放变得比 C++ 中的更复杂,因为 C# 中对象的销毁不是确定性的。

编译:二进制文件与字节码
C++ 立即编译成机器二进制代码。 C# 被编译成字节码,然后由 .NET 编译成机器二进制代码。 (以前的“.NET Core”,.NET 是微软对原始 .NET 框架的现代跨平台替代品。)
尽管 C++ 在这些不同的编译方法中具有性能优势,但 C# 具有称为“反射”的强大功能,它可以使用在运行时收集的信息进行对象实例化和方法调用。 例如,可以通过名称调用方法,尽管该方法在编译期间不可用。 根据定义,C++ 不能有反射,因为它是立即编译的。 C++ 具有运行时类型信息 (RTTI)。 这是一个不太强大的功能,因为它仅用于具有虚函数的类型。
C++ 还具有在编译时根据变量类型生成的代码形式的模板。 C# 没有模板,而是有泛型。 泛型不是在编译时解析,而是在运行时解析。 因此,模板比泛型更快。 另一方面,泛型不需要为每个新变量类型增加额外的内存。
功能比较
| 特征 | C++ | C# |
|---|---|---|
| 汇编 | 直接转二进制 | 字节码 |
| 编译时间 | 长 | 短的 |
| 内存管理 | 通过智能指针手动或半自动 | 由垃圾收集器自动执行 |
| 运行时速度 | 尽可能快地 | 比 C++ 慢 |
| 运行时内存要求 | 最佳的 | 超过 C++ |
| 容易出错 | 对于没有经验的程序员来说容易出错 | 更适合初学者 |
| 类继承 | 单个、多个和虚拟 | 单只,多带接口 |
| 通用代码 | 模板——编译时间 | 泛型——运行时 |
| 可移植性 | 编译器可用于几乎所有操作系统,但需要为每个目标编译代码 | 编译后的字节码可以在许多操作系统上运行 |
| 学习 | 陡峭的学习曲线; 耗时的; 对于新手开发人员来说可能很复杂; 较小的社区,生产的学习资源较少 | 高级语言; 更容易阅读; 上层阶级层次结构; 初学者更容易掌握,尤其是有 C++ 或 Java 经验的人; 更大更活跃的社区 |
| 反射 | 不可用的运行时类型信息是一个糟糕的替代品 | 可用且非常方便 |
| 隐式转换 | 允许内置类型 | 仅在安全时才允许 |
| 与 C 的兼容性 | 完全兼容外部 C 代码 | 不兼容 |
| 模块化 | 完成了库和标题 | 内置在语言中 |
C# 与 C++:哪种语言更好?
在速度和内存效率方面,C++ 无疑是赢家。 但是,如果一个好的 C# 库很容易获得,但没有这样的库可用于 C++,那么 C# 最终可能会产生一个更快的解决方案,而 C++ 的实现可能会变得更慢。
在 C# 中开发通常更快。 如果应用程序不执行时间要求严格的任务,那么选择更容易且不易出错的语言是有意义的。
传统上,C++ 是非 Windows 环境的正确选择,但是一旦微软开始鼓励 .NET 的开源实现,情况就发生了变化。 相同的 C# 字节码几乎可以在任何平台上运行,这使其成为简化可移植性的首选语言。
由于反射,在编写必须支持远程函数调用或需要使用运行时可用信息生成代码的类似功能的库时,C# 是更合理的选择。
尽管这两种语言都支持模块化设计,但在 C++ 中更难维护,C++ 使用 C 设计的标头来实现该功能——这种方法现在已被更现代的方法所超越。 这通常会导致 C++ 编译时间明显长于 C# 到字节码的编译时间。
C++ 是一种更复杂的语言,因此 C++ 程序员可以更容易地转向 C#,而不是相反。 但是,如果您的团队同时包含 C++ 和 C# 开发人员,则可以混合使用这两种语言。
选择正确的语言
如果您需要高性能,几乎所有情况下的答案都是 C++。 “高性能”是指代码。 如果您将现成的库用于时间紧迫的工作,则代码的性能可能不是决定性因素。
如果性能不重要,则需要考虑开发时间。 如果您可以从头开始,使用 C# 开发项目可能是更好的选择。
如果您有一些开发时间,但性能并不重要,则选择取决于可用开发人员的技能。 请记住,您的开发人员的流利程度可能会严重影响未来的代码维护。 只要有可能,请考虑您的团队喜欢的语言。
