如果您已经了解 C# 或 Java,如何学习 C++
注意:本节需要更多内容
本节包含初步信息,但需要更多常见问题解答。如果您能提供 C# 或 Java 程序员转向 C++ 时常问的问题,请将鼠标悬停在任何常见问题标题上,然后点击“建议改进”图标。(如果您还能提供问题的大致答案,那就太好了,但这不是强制性的。)
C++ 和 C#/Java 有什么区别?
这三种语言都完全支持面向对象范式。没有哪种语言在所有情况下都“比其他语言更好”。但它们之间存在差异。最重要的差异是:
为什么 C++ 没有一个通用的 Object 类?
- 我们不需要它:在大多数情况下,泛型编程提供了静态类型安全的替代方案。其他情况则通过多重继承处理。
- 没有有用的通用类:一个真正通用的类不携带自己的语义。
- “通用”类鼓励对类型和接口的草率思考,并导致过度的运行时检查。
- 使用通用基类意味着成本:对象必须在堆上分配才能具有多态性;这意味着内存和访问成本。堆对象不自然地支持复制语义。堆对象不支持简单的作用域行为(这使得资源管理复杂化)。通用基类鼓励使用
dynamic_cast
和其他运行时检查。
是的,以上简化了论点。这是一个常见问题解答,而不是学术论文。
“泛型”是模板本应有的样子吗?
不是。C++ 模板支持 C# 和 Java 泛型的严格超集——你在 C# 或 Java 中能做的任何事情,你都可以在 C++ 中做,而且能做更多。本常见问题解答总结了这些能力。
Java 和 C# 中的泛型主要是抽象类和虚函数调用的语法糖;也就是说,使用泛型(无论是 Java 还是 C# 泛型),你都针对精确定义的接口进行编程,并且通常会为使用参数支付虚函数调用和/或动态转换的成本。你也可以在 C++ 中做同样的事情,通过使用 container<InterfacePtr>
,其中 InterfacePtr
可以是任何合适的原始或智能指针类型,例如不拥有其对象的 vector<Base*>
,或者拥有其对象并会及时且确定性地销毁和释放它们的 list<unique_ptr<Base>>
。
但模板超越了这一点,通过整数模板参数、特化以及内置类型和用户定义类型的统一处理等特性组合,支持泛型编程、模板元编程等。你可以为模板实例化为特定类型或类型子集时编写特殊情况代码。你可以像使用内置类型一样轻松地使用类类型。你可以传递非类型参数,例如带有编译时信息的整数,如数组的固定大小(例如,std::array<widget,10>
是一个固定大小的 array
,包含 10
个 widget
类型的对象)。还有更多……结果是“泛型”无法比拟的灵活性、通用性和性能。STL 就是最好的例子。
因此,C# 和 Java 的“泛型”特性得到了完全支持,但这只是一个更通用、更具表现力、更高性能的特性中的一个狭窄特例。举一个简单的例子,但对性能影响很大的真实例子是,C++ 支持 vector<AnyType>
,无论 AnyType
是什么类型,都具有真正的连续存储,这在 C# 和 Java 中是不可能实现的,在 C# 和 Java 中,连续存储只用于内置类型,在 C# 中也用于结构体,而不是用于类类型,类类型占绝大多数。
公平地说,C++ 模板灵活性一个不太理想的结果是错误发现较晚以及错误消息极其糟糕。目前正通过约束类间接解决此问题,并将很快通过直接针对此问题的即将推出的 Concepts 语言特性直接解决。