Learning C++ if you already know C# or Java
Note: This section needs more material
This section contains initial information but needs additional FAQs. If you can supply a common question asked by C# or Java programmers coming to C++, please hover over any FAQ title and click the icon for “recommend an improvement.” (If you can also supply a sketch of an answer along with the question, that would be great but is optional.)
What’s the difference between C++ and C#/Java?
All three languages fully support the OO paradigm. Neither is categorically and universally “better” than the other. But there are differences. The most important differences are:
Why doesn’t C++ have a universal class Object?
- We don’t need one: Generic programming provides statically type safe alternatives in most cases. Other cases are handled using multiple inheritance.
- There is no useful universal class: A truly universal carries no semantics of its own.
- A “universal” class encourages sloppy thinking about types and interfaces and leads to excess run-time checking.
- Using a universal base class implies cost: Objects must be heap-allocated to be polymorphic; that implies memory and access cost. Heap objects don’t naturally support copy semantics. Heap objects don’t support simple scoped behavior (which complicates resource management). A universal base class encourages use of
dynamic_castand other run-time checking.
Yes, the above simplifies the arguments. This is a FAQ, not an academic paper.
Is “generics” what templates should have been?
No. C++ templates support a strict superset of C# and Java generics – everything you can do in C# or Java, you can do in C++, and a lot more. This FAQ summarizes those capabilities.
Generics in Java and C# are primarily syntactic sugar for abstract classes and virtual function calls; that is, with generics (whether Java or C# generics), you program against precisely defined interfaces and typically pay the cost of virtual function calls and/or dynamic casts to use arguments. You can do the same in C++, by using
InterfacePtr can be any appropriate raw or smart pointer type, for example
vector<Base*> that doesn’t own its objects or
list<unique_ptr<Base>> that does own its objects and will destroy and free them promptly and deterministically.
But templates go beyond that, and support generic programming, template metaprogramming, etc. through a combination of features such as integer template arguments, specialization, and uniform treatment of built-in and user-defined types. You can write special case code for when your template is instantiated with a specific type or a subset of types. You can use class types just as easily as built-in types. You can pass non-type parameters, like integers with compile-time information like the fixed size of an array (e.g.,
std::array<widget,10> is a fixed-size
10 objects of type
widget). And more… The result is flexibility, generality, and performance unmatched by “generics”. The STL is the prime example.
So the “generics” features of C# and Java are fully supported, but as just one narrow special case or a much more general, expressive, and high-performance feature. As a simple example, but a real one that matters a lot for performance, C++ supports
vector<AnyType> with true contiguous storage no matter what type
AnyType is, which is not possible in C# and Java where contiguous storage is only for the built-in types and in C#’s case also structs, not for class types which are the vast majority of types.
For balance, note that a less desirable result of C++’s template flexibility is late detection of errors and horrendously bad error messages. This is currently being addressed indirectly with constraints classes, and soon directly by the upcoming Concepts language feature that directly targets this problem.