
C++ (C Plus Plus) is an object-oriented high-level programming language that extends and upgrades the C language. It was developed in 1979 by Bjarne Stroustrup at AT&T Bell Labs. Initially, C++ was referred to as “C With Classes”. It is a general-purpose programming language that supports static data type checking and multiple programming paradigms, including procedural programming, data abstraction, object-oriented programming, and generic programming.
C++ inherits from C, further expanding and refining it into an object-oriented programming language. C++ can perform procedural programming as in C, object-oriented programming characterized by abstract data types, and object-oriented programming characterized by inheritance and polymorphism. C++ can create virtually any type of program: games, device drivers, HPC, cloud, desktop, embedded, and mobile applications. It is even used to write libraries and compilers for other programming languages.
C++ possesses practical features for computer operation while also aiming to improve the programming quality of large-scale programs and the problem description capabilities of programming languages.
Introduction
C++ is a general-purpose programming language created by Bjarne Stroustrup as an extension of the C programming language, or “C With Classes”. Over time, the language has undergone significant expansion. Modern C++ now includes object-oriented, generic, and functional features in addition to tools for low-level memory operations. It is almost always implemented as a programming language, with many vendors providing C++ compilers, including the Free Software Foundation, LLVM, Microsoft, Intel, Oracle, and IBM, making it available on many platforms.
The design of C++ is oriented towards system programming and embedded, resource-constrained software, as well as large systems, with highlights on performance, efficiency, and flexibility of use. C++ is also useful in many other environments, with its main advantages being software infrastructure and resource-constrained applications, including desktop applications, video games, servers (such as e-commerce, web search, or SQL servers), and performance-critical applications (such as telephone switches or space probes).
C++ is standardized by the International Organization for Standardization (ISO), with the latest standard version approved and published in December 2020 as ISO/IEC 14882:2020 (informally known as C++20). The C++ programming language was first standardized in 1998 as ISO/IEC 14882:1998, followed by revisions in C++03, C++11, C++14, and C++17. The current C++20 standard replaces these with new features and an expanded standard library. Before its first standardization in 1998, C++ had been developed by Danish computer scientist Bjarne Stroustrup at Bell Labs since 1979 as an extension of the C language; he wanted a language similar to C that was efficient and flexible, while also providing high-level features for program organization. Since 2012, the release schedule for C++ has been every three years, with the next planned standard being C++23.
Development History
In 1979, Danish computer scientist Bjarne Stroustrup began researching “C with Classes”, the precursor to C++. The motivation for creating the new language stemmed from Stroustrup’s programming experiences during his doctoral thesis. Stroustrup found that Simula had features very helpful for large software development, but the language was too slow for practical use, while BCPL was fast but too low-level for large software development. When Stroustrup started working at AT&T Bell Labs, he encountered problems analyzing the UNIX kernel in distributed computing. Remembering his doctoral experiences, Stroustrup began enhancing the C language with features from Simula. The choice of C was due to its generality, speed, portability, and widespread use. In addition to the influences of C and Simula, other languages also impacted this new language, including ALGOL 68, Ada, CLU, and ML.
Initially, Stroustrup’s “C with Classes” added features to the C compiler Cpre, including classes, derived classes, strong typing, inline functions, and default parameters.
In 1982, Stroustrup began developing the successor to C with classes, and after several other names, he named it “C++” (the increment operator in C). New features were added, including virtual functions, function name and operator overloading, references, constants, type-safe dynamic memory allocation (new/delete), improved type checking, and BCPL-style single-line comments with two forward slashes (//). Additionally, Stroustrup developed a new standalone compiler for C++ called Cfront.
In 1984, Stroustrup implemented the first stream input/output library. Doug McIlroy proposed the idea of providing an output operator instead of named output functions (he had previously suggested using Unix pipes).
In 1985, the first edition of “The C++ Programming Language” was published, which became the authoritative reference for the language as there was no official standard yet. The first commercial implementation of C++ was released in October of the same year.
In 1989, C++2.0 was released, followed by an updated second edition of “The C++ Programming Language” in 1991. New features in 2.0 included multiple inheritance, abstract classes, static member functions, const member functions, and protected members. In 1990, “The C++ Reference Manual with Annotations” was published. This work became the foundation for future standards. Later added features included templates, exceptions, namespaces, new type conversions, and boolean types.
In 1998, C++98 was released, standardizing the language, with a minor update released in 2003 (C++03).
After C++98, the development of C++ was relatively slow until the release of the C++11 standard in 2011, which added many new features, further expanded the standard library, and provided more conveniences for C++ programmers. Following a minor update in December 2014 (C++14), various new features were introduced in C++17. After finalization in February 2020, the C++20 standard draft was approved on September 4, 2020, and officially released on December 15, 2020.
On January 3, 2018, Stroustrup was announced as the recipient of the 2018 Charles Stark Draper Engineering Award, “in recognition of his conceptualization and development of the C++ programming language.”
As of 2021, C++ ranked fourth in the TIOBE index, which measures the popularity of programming languages, following C, Java, and Python.
Etymology
According to Stroustrup, “the name reflects the evolutionary nature of the changes to the C language.” The name is credited to Rick Mascitti (mid-1983) and was first used in December 1983. In 1992, when Mascitti was informally asked about the name, he stated that it was a joke. The name derives from the operator in C (which increments the value of a variable) and the common naming convention of using “+” to indicate enhancement of a computer program.
During the development of C++, the language was referred to as “New C” and “C with Classes” before obtaining its final name.
Philosophy
Throughout its lifecycle, C++ has developed and evolved following a series of principles:
-
It must be driven by practical problems, and its features should be immediately useful in real-world programs.
-
Each feature should be implementable (in a reasonably obvious way).
-
Programmers should be free to choose their programming style, which should be fully supported by C++.
-
Allowing a useful feature is more important than preventing any possible misuse of C++.
-
It should provide facilities for organizing projects into separate, well-defined parts and for combining separately developed parts.
-
No implicit violations of the type system (but explicit violations are allowed; i.e., violations requested explicitly by the programmer).
-
User-defined types need to have the same support and performance as built-in types.
-
Unused features should not negatively impact the executable created (e.g., performance degradation).
-
No language should exist beneath C++ (except for assembly language).
-
C++ should work with other existing programming languages rather than fostering its own independent and incompatible programming environment.
-
If the programmer’s intent is unknown, allow the programmer to specify it by providing manual control.
Standardization
C++ is standardized by an ISO working group known as JTC1/SC22/WG21. So far, it has released six revisions of the C++ standard, and the next revision C++23 is currently in development.
| Year | C++ Standard | Informal Name |
|---|---|---|
| 1998 | ISO/IEC 14882:1998 | C++98 |
| 2003 | ISO/IEC 14882:2003 | C++03 |
| 2011 | ISO/IEC 14882:2011 | C++11, C++0x |
| 2014 | ISO/IEC 14882:2014 | C++14, C++1y |
| 2017 | ISO/IEC 14882:2017 | C++17, C++1z |
| 2020 | ISO/IEC 14882:2020 | C++20, C++2a |
Language
The C++ language has two main components: a direct mapping of hardware features primarily provided by a subset of C, and zero-cost abstractions based on these mappings. Stroustrup describes C++ as “a lightweight abstraction programming language designed to build and use efficient and elegant abstractions”; “providing both hardware access and abstraction is fundamental to C++. Efficiently implementing this is what distinguishes it from other languages.”
C++ inherits most of the syntax of C. Below is a version of Bjarne Stroustrup’s Hello World program, which uses C++ standard library stream tools to write a message to standard output:
#include <iostream>
int main (){
std::cout << "Hello, world!\n";
return 0;
}
Object Storage
Like C, C++ supports four types of memory management: static storage duration objects, thread storage duration objects, automatic storage duration objects, and dynamic storage duration objects.
Static Storage Duration Objects
Static storage duration objects are created before input and destroyed in the reverse order of creation after exit. The standard does not specify the exact order of creation (although some rules are defined below) to allow for some freedom in how implementations are organized. More formally, the lifetime of such objects “should last for the duration of the program.”
Static storage duration objects are initialized in two phases. First, “static initialization” is performed, and only after all static initialization has been executed is “dynamic initialization” performed. In static initialization, all objects are first zero-initialized; afterwards, all objects with constant initialization phases are initialized with constant expressions (i.e., literals or initialized variables). Although not specified in the standard, the static initialization phase can be completed at compile time and stored in the executable’s data partition. Dynamic initialization involves all object initialization completed through constructors or function calls (unless the function is marked in C++11). The order of dynamic initialization is defined as the order of declarations within a compilation unit (i.e., the same file). No guarantees are provided for the initialization order between compilation units.
Thread Storage Duration Objects
This type of variable is very similar to static storage duration objects. The main difference is that creation occurs before the thread is created, and destruction is completed after the thread joins.
Automatic Storage Duration Objects
The most common type of variable in C++ is local variables and temporary variables within functions or blocks. The common characteristic of automatic variables is that their lifetime is limited to the scope of the variable. They are created upon declaration and may be initialized (as detailed below), and when the scope exits, they are destroyed in the reverse order of creation. This is achieved through allocation on the stack.
Local variables are created when the execution point passes the declaration point. If the variable has a constructor or initializer, it is used to define the initial state of the object. When the local block or function declaring the local variable closes, the local variable is destroyed. The C++ destructor for local variables is called at the end of the object’s lifetime, allowing for a resource management protocol known as RAII, which is widely used in C++.
Member variables are created when the parent object is created. Array members are initialized in order from 0 to the last member of the array. When the parent object is destroyed in the reverse order of creation, member variables are also destroyed. That is, if the parent object is an “automatic object”, it will be destroyed when it goes out of scope, triggering the destruction of all its members.
Temporary variables are the result of expression evaluations, and when the statement containing the expression is fully evaluated (usually at the end of the statement), the temporary variable is destroyed.
Dynamic Storage Duration Objects
These objects have a dynamic lifetime and can be created directly by calling and explicitly destroyed by calling. The “C++ Core Guidelines” recommend not using raw pointers to create dynamic objects directly, but rather supporting smart pointers through single ownership and reference counting, which were introduced in C++11.
Templates
C++ templates support generic programming. C++ supports function, class, alias, and variable templates. Templates can be parameterized by types, compile-time constants, and other templates. Templates are instantiated at compile time. To instantiate a template, the compiler replaces the template parameters with specific parameters to generate concrete function or class instances. Some substitutions are impossible; the overloading resolution strategy described by the phrase “substitution failure is not an error” (SFINAE) eliminates these issues. Templates are a powerful tool for generic programming, template metaprogramming, and code optimization, but this capability comes at a cost. The use of templates may increase code size because each template instantiation generates a copy of the template code: each set of template parameters corresponds to one copy; however, if the code is hand-written, the amount of generated code is the same or less. This contrasts sharply with runtime generics in other languages (like Java), where types are erased at compile time, and a single template body is retained.
Templates differ from macros: while both compile-time language features support conditional compilation, templates are not limited to lexical replacement. Templates are aware of the semantics and type system of their host language, as well as all compile-time type definitions, and can perform advanced operations, including programmatic flow control based on strictly type-checked parameters. Macros can conditionally control compilation based on predefined criteria but cannot instantiate new types, recurse, or perform type evaluations, effectively being limited to pre-compiled text replacement and text inclusion/exclusion. In other words, macros can control the compilation flow based on predefined symbols, but unlike templates, macros cannot independently instantiate new symbols. Templates are tools for static polymorphism (see below) and generic programming.
Additionally, templates are Turing complete compile-time mechanisms in C++, meaning that any computation expressible by a computer program can be computed in some form by template metaprogramming before runtime.
In summary, templates are compile-time parameterized functions or classes written without knowing the specific parameters used to instantiate them. After instantiation, the generated code is equivalent to code specifically written for the passed parameters. In this way, templates provide a method to decouple the general, broadly applicable aspects of functions and classes (encoded in the template) from the specific aspects (encoded in the module parameters) without sacrificing performance due to abstraction.
Objects
C++ introduces object-oriented programming (OOP) features to C. It provides classes that offer four common features found in OOP (and some non-OOP) languages: abstraction, encapsulation, inheritance, and polymorphism. A notable feature of C++ classes compared to classes in other programming languages is the support for deterministic destructors, which in turn supports the concept of Resource Acquisition Is Initialization (RAII).
Encapsulation
Encapsulation is the hiding of information to ensure that data structures and operators are used as intended, making the usage model more apparent to developers. C++ provides the ability to define classes and functions as its primary encapsulation mechanism. In a class, members can be declared as public, protected, or private to explicitly enforce encapsulation. Any function can access the public members of a class. Private members can only be accessed by member functions of that class and functions and classes explicitly granted access by that class (“friends”). Members inherited from a class can also access protected members, except for the class itself and any friends.
The principles of object-oriented programming ensure that only functions that access the internal representation of a type can do so. C++ supports this principle through member functions and friend functions but does not enforce it. Programmers can declare part or all of a type’s representation as public, allowing them to make public entities not belong to the type’s representation. Therefore, C++ supports not only object-oriented programming but also other decomposition paradigms, such as modular programming.
It is generally considered good practice to set all data as private or protected and only expose functions as part of a minimal interface for class users. This can hide the details of data implementation, allowing designers to fundamentally change the implementation later without changing the interface in any way.
Inheritance
Inheritance allows one data type to acquire the properties of another data type. Inheritance from a base class can be declared as public, protected, or private. This access specifier determines whether unrelated classes and derived classes can access the inherited public and protected members of the base class. Only public inheritance corresponds to what is commonly referred to as “inheritance”. The other two forms are used much less frequently. If the access specifier is omitted, a “class” will inherit privately, while a “struct” will inherit publicly. A base class can be declared as virtual; this is known as virtual inheritance. Virtual inheritance ensures that only one instance of the base class exists in the inheritance graph, avoiding some ambiguities of multiple inheritance.
Multiple inheritance is a feature of C++ that allows a class to derive from multiple base classes; this allows for more refined inheritance relationships. For example, a “Flying Cat” class can inherit from both “Cat” and “Flying Mammal”. Other languages, such as C# or Java, achieve similar functionality (though more limited) by allowing multiple interfaces to be inherited while limiting the number of base classes to one (interfaces differ from classes in that they only provide declarations of member functions without implementations or member data). Interfaces in C# and Java can be defined in C++ as classes that contain only pure virtual functions, commonly referred to as abstract base classes or “ABCs”. The member functions of these abstract base classes are typically explicitly defined in derived classes rather than inherited implicitly. C++ virtual inheritance has a feature known as ambiguity resolution.
Operators and Operator Overloading
C++ provides over 35 operators covering basic arithmetic, bitwise operations, indirection, comparison, logical operations, and more. Almost all operators can be overloaded for user-defined types, but there are some notable exceptions, such as member access (.) and (.*) as well as the conditional operator. The rich set of overloadable operators is central to making user-defined types in C++ appear like built-in types.
Overloaded operators are also an important part of many advanced C++ programming techniques (such as smart pointers). Overloaded operators do not change the precedence of the calculations involving the operators nor do they change the number of operands used with the operators (however, operators can ignore any operands, although they will be evaluated before execution). The overloaded “&&” and “||” operators will lose their short-circuit evaluation properties.
Polymorphism
Polymorphism provides a common interface for many implementations and allows objects to behave differently in different situations.
C++ supports both static (resolved at compile time) and dynamic (resolved at runtime) polymorphism, supported by the aforementioned language features. Compile-time polymorphism does not allow certain runtime decisions, while runtime polymorphism often incurs performance penalties.
Static Polymorphism
Function overloading allows programmers to declare multiple functions with the same name but different parameters (i.e., ad hoc polymorphism). Functions are distinguished by the number or type of their formal parameters. Thus, the same function name can refer to different functions depending on the context in which it is used. The return type of the function is not used to distinguish overloaded functions and will lead to compile-time error messages.
When declaring a function, programmers can specify default values for one or more parameters. Doing so allows optional omission of parameters with default values when calling the function, in which case the default parameters will be used. When calling a function with fewer parameters than declared, explicit parameters will be matched to parameters from left to right, and any unmatched parameters at the end of the parameter list will be assigned their default parameters. In many cases, specifying default parameters in a single function declaration is preferable to providing overloaded function definitions with different numbers of parameters.
Templates in C++ provide a complex mechanism for writing generic polymorphic code (i.e., parameter polymorphism). In particular, through a peculiar repeated template pattern, a form of static polymorphism can be achieved that is very similar to the syntax of overriding virtual functions. Because C++ templates are type-aware and Turing complete, they can also be used to allow the compiler to resolve recursive conditions and generate substantial programs through template metaprogramming. Contrary to some views, template code does not generate bulk code when compiled with appropriate compiler settings.
Dynamic Polymorphism
Inheritance
In C++, pointers and references to variables of base class types can also refer to objects of any derived class of that type. This allows arrays and other types of containers to hold pointers to different types of objects (references cannot be held directly in containers). This implements dynamic (runtime) polymorphism, where the referenced object can behave differently based on its (actual, derived) type.
C++ also provides the dynamic_cast operator, which allows code to safely attempt to convert an object to a more derived type through base references/pointers: downcasting. The attempt is necessary because one often does not know which derived type is being referenced. (Upcasting, converting to a more general type, can always be checked/performed at compile time through static_cast since ancestor classes are specified in the derived class’s interface and are visible to all callers.) If a dynamic_cast to a pointer fails, the result is a nullptr constant, while if the target is a reference (which cannot be null), the cast will throw an exception. Objects known to have a certain derived type can be converted to that type using static_cast, bypassing the safety runtime type checks of RTTI and dynamic_cast, so this method should only be used when the programmer is very confident that the conversion is valid and will always be valid.
Virtual Member Functions
Typically, when a function in a derived class overrides a function in a base class, the function to be called is determined by the type of the object. When there is no difference in the number or type of parameters between two or more definitions of a given function, that function will be overridden. Therefore, at compile time, given a base class pointer, it may not be possible to determine the type of the object, and thus the correct function to call; hence, that decision is deferred until runtime. This is known as dynamic dispatch. Virtual member functions or methods allow the most specific implementation of a function to be called based on the actual runtime type of the object. In C++ implementations, this is typically accomplished using a virtual function table. If the object type is known, this can be bypassed by adding a fully qualified class name before the function call, but generally, calls to virtual functions are resolved at runtime.
In addition to standard member functions, operator overloads and destructors can also be virtual. As a rule of thumb, if any function in a class is virtual, the destructor should also be virtual. Since the type of an object at creation time is known at compile time, constructors and extended copy constructors cannot be virtual. Nevertheless, situations may arise where a pointer to a derived object is passed as a pointer to a base object, necessitating the creation of a copy of the object. In such cases, a common solution is to create a clone (or similar) virtual function that creates and returns a copy of the derived class when called.
By appending =0 after the right parenthesis and before the semicolon, a member function can also be made a “pure virtual” function. Classes containing pure virtual functions are called abstract classes. Objects cannot be created from abstract classes; they can only be derived from. Any derived class will inherit the virtual function as a pure function and must provide its non-pure definition (as well as all other pure virtual functions) before objects of the derived class can be created. Attempting to create class objects with pure virtual member functions or inherited pure virtual member functions is a formatting error.
Lambda Expressions
C++ supports anonymous functions, also known as lambda expressions, which take the following form:
[capture](parameters) -> return_type { function_body }
If the lambda has no parameters, it can be omitted, i.e.,
[capture] -> return_type { function_body }
Additionally, if possible, the return type of the lambda expression can be automatically inferred, for example:
[](int x, int y) { return x + y; } // inferred
[](int x, int y) -> int { return x + y; } // explicit
The [capture] list supports the definition of closures. This lambda expression is defined in the standard as syntactic sugar for unnamed function objects.
Exception Handling
Exception handling is used to propagate the existence of runtime problems or errors from the point of detection to a location that can handle the problem. It allows this to be done in a unified manner, separate from the main code, while detecting all errors. If an error occurs, an exception is thrown (raised) and then caught by the nearest appropriate exception handler. Exceptions cause the current scope to exit, as well as each outer scope (propagation), until a suitable handler is found, and the destructors of any objects in those exit scopes are called in turn. At the same time, exceptions present themselves as objects carrying data about the detected problem.
Some C++ style guides, such as those from Google, LLVM, and Qt, prohibit the use of exceptions.
Code that may cause exceptions is placed in a try block. Exceptions are handled in separate catch blocks (handlers); each try block can have multiple exception handlers, as shown in the following example.
Standard Library
The C++ standard consists of two parts: the core language and the standard library. C++ programmers expect the latter to be present in every major implementation of C++; it includes aggregate types (vectors, lists, maps, sets, queues, stacks, arrays, tuples), algorithms (find, for_each, binary_search, random_shuffle, etc.), input/output facilities (iostream for reading and writing from the console and files), filesystem libraries, localization support, smart pointers for automatic memory management, regular expression support, multithreading libraries, atomic support (allowing at most one thread to read or write a variable at a time without any external synchronization), time utilities (for measuring, getting the current time, etc.), a system for converting error reporting that does not use C++ exceptions into C++ exceptions, a random number generator, and a slightly modified version of the C standard library (to conform to the C++ type system).
A large part of the C++ library is based on the Standard Template Library (STL). Useful tools provided by the STL include containers (such as vectors and lists) as collections of objects, iterators that provide array-like access to containers, and algorithms that perform operations such as searching and sorting.
Additionally, (multi)maps (associative arrays) and (multi)sets are provided, all of which export compatible interfaces. Thus, using templates, generic algorithms can be written that are applicable to any sequence defined by any container or iterator. As in C, the library’s functionality is accessed by including standard headers using the #include directive. The C++ standard library provides 105 standard header files, of which 27 have been deprecated.
The standard adopted the STL, originally designed by Alexander Stepanov, who had been experimenting with generic algorithms and containers for years. When he began using C++, he finally found a language that could create generic algorithms (such as STL sort) that performed better than C standard library qsort, thanks to features like C++’s inline and compile-time binding rather than function pointers. The standard does not refer to it as “STL” since it is merely part of the standard library, but the term is still widely used to distinguish it from other parts of the standard library (input/output streams, internationalization, diagnostics, C library subsets, etc.).
Most C++ compilers, as well as all major compilers, provide a standard-compliant implementation of the C++ standard library.
C++ Core Guidelines
The C++ Core Guidelines are an initiative led by C++ creator Bjarne Stroustrup and Herb Sutter, chair of the C++ ISO working group, aimed at helping programmers write “modern C++” by using best practices of the language standard from C++14 and beyond, and assisting developers of compilers and static analysis tools in formulating rules to catch bad programming practices.
The main goal is to write type and resource-safe C++ efficiently and consistently.
The core guidelines were announced in the opening keynote of CPPC in 2015.
The guidelines are accompanied by a Guidelines Support Library (GSL), which is a header-only library of types and functions for implementing the core guidelines and executing static analysis tools for the guidelines’ rules.
Compatibility
To give compiler vendors greater freedom, the C++ standards committee decided not to mandate the implementation of name mangling, exception handling, and other implementation-specific features. The downside of this decision is that the target code generated by different compilers is expected to be incompatible. However, attempts have been made to standardize compilers for specific machines or operating systems (such as C++ ABI), although they now seem to have been largely abandoned.
Relationship with C
C++ is often considered a superset of C, but strictly speaking, it is not. Most C code can be compiled correctly in C++ with little effort, but there are also some differences that cause some valid C code to be invalid or behave differently in C++. For example, C allows implicit conversions from void* to other pointer types, but C++ does not (for type safety reasons). Additionally, C++ defines many new keywords, such as new and class, which can be used as identifiers (e.g., variable names) in C programs.
The C standard revised in 1999 (C99) eliminated some incompatibilities and now supports C++ features such as line comments (//) and mixed declarations with code. On the other hand, C99 introduced many new features not supported by C++, which are incompatible or redundant in C++, such as variable-length arrays, native complex types (however, the std::complex class in the C++ standard library provides similar functionality, albeit not compatible with code), designated initializers, compound literals, and the restrict keyword. Some features introduced in C99 were included in subsequent versions of the C++ standard, such as C++11 (these features are not redundant). However, the C++11 standard introduced new incompatibilities, such as disallowing string literals to be assigned to character pointers, which remains valid.
To mix C and C++ code, any function declarations or definitions that are called/used in both C and C++ must be declared with C linkage by placing them in an extern "C" {/*...*/} block. Such functions may not rely on features that depend on name mangling (i.e., function overloading).