The reader should be forewarned that extensive knowledge of theCprogramming language is actually assumed. TheC++ Annotations continue wheretopics of theC programming language end, such as pointers, basic flowcontrol and the construction of functions.
Some elements of the language, like specific lexical tokens (likedigraphs (e.g.,<: for[, and>: for])) are not coveredby theC++ Annotations, as these tokens occur extremely seldom inC++ sourcecode. In addition,trigraphs (using??< for{, and??> for}) have been removed fromC++.
The working draft of theC++ standard is freely available, and can becloned from the git-repository athttps://gitlab.com/cplusplus/draft.git
The version number of theC++ Annotations (currently 13.02.02) is updated whenthe content of the document change. The first number is the major number, andis probably not going to change for some time: it indicates a majorrewriting. The middle number is increased when new information is added to thedocument. The last number only indicates small changes; it is increased when,e.g., series of typos are corrected.
This document is published by the Center of Information Technology,University of Groningen,the Netherlands under theGNU General Public License.
TheC++ Annotations were typeset using theyodlformatting system.
All correspondence concerning suggestions, additions, improvements or changes to this document should be directed to the author:
Frank B. Brokken
University of Groningen,
PO Box 407,
9700 AK Groningen
The Netherlands
(email: f.b.brokken@rug.nl)
In this chapter an overview ofC++'s defining features is presented. A fewextensions toC are reviewed and the concepts of object based and objectoriented programming (OOP) are briefly introduced.
POLYMORPHISM about deriving astd::streambuf class that can be used bystd::iostream objects (cf. section14.8.2).__file_clock tofile_clock); removed section 12.3 (allocators, removed in theC++20 standard); included missing examples; and repaired typos.Modules, covers the_name-independent declaration, upgraded theC++ standard toC++26, clarified and repaired typos in several sections.std::iostream class (replaced by section14.8.2 in version 13.02.00).std::byte type (cf. chapter3), offers an alternative implementation (cf. section11.4), and covers the definition of multi-argument index operators (chapter11). The description of how to implement class constructors that may throw exceptions was updated (cf. section10.12).std::iterator is deprecated. Section22.14 was rewritten; section11.1 was updated (operator[] const should returnType const & instead ofType values); added section5.3 coveringstd::string_view; added section20.15 covering synchronization of output to streams in multi-threaded programs; added sections22.10.2.1 and23.13.7.2 about bound-friends; 'typedef' definitions were replaced by 'using' declarations.__file_clock::to_sys static member, repaired the descriptions ofpop*() members of various abstract containers, and reorganized the description of the facilities of thefilesystem::path class.C++ was originally a `pre-compiler', similar to the preprocessor ofC,converting special constructions in its source code to plainC. Back thenthis code was compiled by a standardC compiler. The `pre-code', which wasread by theC++ pre-compiler, was usually located in a file with theextension.cc,.C or.cpp. This file would then be converted to aC source file with the extension.c, which was thereupon compiled andlinked.
The nomenclature ofC++ source files remains: the extensions.cc and.cpp are still used. However, the preliminary work of aC++pre-compiler is nowadays usually performed during the actual compilationprocess. Often compilers determine the language used in a source file from itsextension. This holds true for Borland's and Microsoft'sC++ compilers,which assume aC++ source for an extension.cpp. TheGNUcompilerg++, which is available on many Unix platforms, assumes forC++ the extension.cc.
The fact thatC++ used to be compiled intoC code is also visiblefrom the fact thatC++ is a superset ofC:C++ offers the fullC grammar and supports allC-library functions, and adds to thisfeatures of its own. This makes the transition fromC toC++ quite easy. Programmers familiar withC may start`programming inC++' by using source files having extensions.cc or.cpp instead of.c, and may then comfortably slip into all thepossibilities offered byC++. No abrupt change of habits is required.
LaTeX. After some time, Karel rewrote thetext and converted the guide to a more suitable format and (of course) toEnglish in September 1994.The first version of the guide appeared on the net in October 1994. By then itwas converted toSGML.
Gradually new chapters were added, and the content was modified and furtherimproved (thanks to countless readers who sent us their comments).
In major version four Frank added new chapters and converted the document fromSGML toyodl.
TheC++ Annotations are freely distributable. Be sure to read thelegal notes.If you like this document, tell your friends about it. Even better, let usknow by sending email toFrank.Reading the annotations beyond this point implies that you are aware of these notes and that you agree with them.
.cc and run it throughaC++ compiler:sizeof('c') equalssizeof(int),'c' beingany ASCII character. The underlying philosophy is probably thatchars,when passed as arguments to functions, are passed as integersanyway. Furthermore, theC compiler handles a character constant like'c' as an integer constant. Hence, inC, the function callsputchar(10);
and
putchar('\n');are synonymous.
By contrast, inC++,sizeof('c') is always 1 (but see also section3.4.2). Anint is still anint, though. As we shall see later(section2.5.4), the two function calls
somefunc(10);
and
somefunc('\n');may be handled by different functions:C++ distinguishes functions notonly by their names, but also by their argument types, which are different inthese two calls. The former using anint argument, the latter achar.
void func();
means that a functionfunc() exists, returning no value. Thedeclaration doesn't specify which arguments (if any) are accepted by thefunction.
However, inC++ the above declaration means that the functionfunc()doesnot accept any arguments at all. Any arguments passed to itresult in a compile-time error.
Note that the keywordextern is not required when declaring functions. Afunction definition becomes a function declaration simply by replacing afunction's body by a semicolon. The keywordexternis required,though, when declaring variables.
Always use the latestC++ standard supported by your compiler. When thelatest standard isn't used by default, but is already partially implemented itcan usually be selected by specifying the appropriate flag. E.g., to use theC++26 standard specify the flag--std=c++26.
Note: in theC++ Annotations it is assumed that the lastest available standardis specified using the--std flag, even if no--std flag has beenspecified.
g++compiler(see alsohttps://docs.microsoft.com/en-us/windows/wsl/about).The GNUg++ compiler's official home page ishttp://gcc.gnu.org, also containinginformation about how to install the compiler in an MS-Windows system.
source.cc':g++ source.cc
This produces a binary program (a.out ora.exe). If the defaultname is inappropriate, the name of the executable can be specified using the-o flag (here producing the programsource):
g++ -o source source.cc
If a mere compilation is required, the compiled module can be produced usingthe-c flag:
g++ -c source.cc
This generates the filesource.o, which can later on be linked toother modules.
C++ programs quickly become too complex to maintain `by hand'. With allserious programming projects program maintenance tools are used. Usually thestandardmake program is used to maintainC++ programs, but goodalternatives exist, like theicmake orccbuild programmaintenance utilities.
It is strongly advised to start using maintenance utilities early in the studyofC++.
Concerning the above allegations ofC++, we support the following, however.
structs,typedefs etc.. From these types other typescan be derived, thus leading tostructs containingstructs and soon. InC++ these facilities are augmented by defining data types which arecompletely `self supporting', taking care of, e.g., their memory managementautomatically (without having to resort to an independently operating memorymanagement system as used in, e.g.,Java).xmalloc andxrealloc are used (allocating the memory or abortingthe program when the memory pool is exhausted). However, with functions likemalloc it is easy to err. Frequently errors inC programs can betraced back to miscalculations when usingmalloc. Instead,C++offers facilities to allocate memory in a somewhat safer way, using itsoperator new.static variables can be used and specialdata types such asstructs can be manipulated by dedicated functions.Using such techniques, data hiding can be implemented even inC; though itmust be admitted thatC++ offers special syntactic constructions, makingit far easier to implement `data hiding' (and more in general:`encapsulation') inC++ than inC.With theC++ Annotations we hope to help the reader when transiting fromCtoC++ by focusing on the additions ofC++ as compared toC and byleaving out plainC. It is our hope that you like this document andmay benefit from it.
Enjoy and good luck on your journey intoC++!
static).In contrast (or maybe better: in addition) to this, an object-based approachidentifies thekeywords used in a problem statement. These keywords arethen depicted in a diagram where arrows are drawn between those keywords todepict an internal hierarchy. The keywords become the objects in theimplementation and the hierarchy defines the relationship between theseobjects. The term object is used here to describe a limited, well-definedstructure, containing all information about an entity: data types andfunctions to manipulate the data. As an example of anobject oriented approach, an illustration follows:
The employees and owner of a car dealer and auto garage company are paid as follows. First, mechanics who work in the garage are paid a certain sum each month. Second, the owner of the company receives a fixed amount each month. Third, there are car salesmen who work in the showroom and receive their salary each month plus a bonus per sold car. Finally, the company employs second-hand car purchasers who travel around; these employees receive their monthly salary, a bonus per bought car, and a restitution of their travel expenses.When representing the above salary administration, the keywords could bemechanics, owner, salesmen and purchasers. The properties of such units are: amonthly salary, sometimes a bonus per purchase or sale, and sometimesrestitution of travel expenses. When analyzing the problem in this manner wearrive at the following representation:
In the hierarchy of objects we would define the dependency between thefirst two objects by letting the car salesmen be `derived' fromthe owner and mechanics.

The overall process in the definition of a hierarchy such as the above startswith the description of the most simple type. Traditionally (and stillencountered with some popular object oriented languages) more complex typesare thereupon derived from the basic type, with each derived type adding somenew functionality. From these derived types, more complex types can again bederivedad infinitum, until a representation of the entire problem can bemade.
Over the years this approach has become less popular inC++ as ittypically results in very tightcoupling among those types, which inturnsreduces rather than enhances the understanding, maintainability andtestability of complex programs. The termcoupling refers to the degree ofindependence between software components: tight coupling means a strongdependency, which is frowned upon inC++. InC++ object orientedprograms more and more favor small, easy to understand hierarchies, limitedcoupling and a developmental process wheredesignpatterns (cf.Gamma et al. (1995)) play a central role.
InC++classes are frequently used to define thecharacteristics ofobjects. Classes contain the necessary functionality todo useful things. Classes generally do not offer all their functionality (andtypicallynone of their data) to objects of other classes. As we will see,classes tend tohide their properties in such a way that they are notdirectly modifiable by the outside world. Instead, dedicated functions areused to reach or modify the properties of objects. Thus class-type objects areable to uphold their own integrity. The core concept here isencapsulationof whichdata hiding is just an example. These concepts are furtherelaborated in chapter7.
main:int main() andint main(int argc, char **argv).Notes:
main isint, andnotvoid;main cannot be overloaded (for other than theabovementioned signatures);return statement at theend ofmain. If omittedmain returns 0;argv[argc] equals 0;char **envp parameter' is not defined by theC++standard and should be avoided. Instead, the global variableextern char **environ should be declared providing access to the program'senvironment variables. Its final element has the value 0;main functionreturns. Using afunction try block (cf. section10.11) formainis also considered a normal end of aC++ program. When aC++ endsnormally, destructors (cf. section9.2) of globally definedobjects are activated. A function likeexit(3) does not normally endaC++ program and using such functions is therefore deprecated.// and endsat the end-of-line marker. The standardC comment, delimited by/* and*/ can still be used inC++: int main() { // this is end-of-line comment // one comment per line /* this is standard-C comment, covering multiple lines */ }Despite the example, it is advisednot to useC type commentinside the body ofC++ functions. Sometimes existing code must temporarilybe suppressed, e.g., for testing purposes. In those cases it's very practicalto be able to use standardC comment. If such suppressed code itselfcontains such comment, it would result in nested comment-lines, resulting incompiler errors. Therefore, therule of thumb is not to useC typecomment inside the body ofC++ functions (alternatively,#if 0 until#endif pair of preprocessor directives could of course also be used).
int main() { printf("Hello World\n"); }often compiles underC, albeit with a warning thatprintf()is an unknown function. ButC++ compilers (should) fail to produce code insuch cases. The error is of course caused by the missing#include <stdio.h> (which inC++ is more commonly included as#include <cstdio> directive).
And while we're at it: as we've seen inC++mainalways usestheintreturn value. Although it is possible to defineintmain() without explicitly defining a return statement, withinmain it isnot possible to use areturn statement without an explicitint-expression. For example:
int main() { return; // won't compile: expects int expression, e.g. // return 1; }Implicit conversions fromvoid * to non-void pointers are notallowed. E.g., the following isn't accepted inC++:
void *none() { return 0; } int main() { int *empty = none(); }const attribute). An example is givenbelow: #include <stdio.h> void show(int val) { printf("Integer: %d\n", val); } void show(double val) { printf("Double: %lf\n", val); } void show(char const *val) { printf("String: %s\n", val); } int main() { show(12); show(3.1415); show("Hello World!\n"); } In the above program three functionsshow are defined, only differingin their parameter lists, expecting anint,double andchar *,respectively. The functions have identical names. Functions having identicalnames but different parameter lists are calledoverloaded. The act ofdefining such functions is called `function overloading'.TheC++ compiler implements function overloading in a rather simpleway. Although the functions share their names (in this exampleshow), thecompiler (and hence the linker) use quite different names. The conversion of aname in the source file to an internally used name is called `name mangling'. E.g., theC++ compiler might convert the prototypevoidshow(int) to the internal nameVshowI, while ananalogous function having achar * argument might be calledVshowCP. The actual names that are used internally depend on the compilerand are not relevant for the programmer, except where these names show up ine.g., a listing of the content of a library.
Some additional remarks with respect to function overloading:
show are stillsomewhat related (they print information to the screen).However, it is also quite possible to define two functionslookup,one of which would find a name in a list while the other would determine thevideo mode. In this case the behavior of those two functions have nothing incommon. It would therefore be more practical to use names which suggest theiractions; say,findname andvideoMode.
printf("Hello World!\n");provides no information about the return value of the functionprintf. Two functionsprintf which only differ in theirreturn types would therefore not be distinguishable to the compiler.
const member functions isintroduced (cf. section7.7). Here it is merely mentionedthat classes normally have so-called member functions associated with them(see, e.g., chapter5 for an informal introduction to theconcept). Apart from overloading member functions using different parameter lists, itis then also possible to overload member functions by theirconst attributes. In those cases,classes may have pairs of identically named member functions, having identicalparameter lists. Then, these functions are overloaded by theirconstattribute. In such cases only one of these functions must have theconstattribute. #include <stdio.h> void showstring(char *str = "Hello World!\n"); int main() { showstring("Here's an explicit argument.\n"); showstring(); // in fact this says: // showstring("Hello World!\n"); }The possibility to omit arguments in situations where default argumentsare defined is just a nice touch: it is the compiler who supplies the lackingargument unless it is explicitly specified at the call. The code of theprogram will neither be shorter nor more efficient when default arguments areused.
Functions may be defined with more than one default argument:
void two_ints(int a = 1, int b = 4); int main() { two_ints(); // arguments: 1, 4 two_ints(20); // arguments: 20, 4 two_ints(20, 5); // arguments: 20, 5 }When the functiontwo_ints is called, the compiler supplies one or twoarguments whenever necessary. A statement liketwo_ints(,6) is, however,not allowed: when arguments are omitted they must be on the right-hand side.
Default arguments must be known atcompile-time since at that momentarguments are supplied to functions. Therefore, the default arguments must bementioned at the function'sdeclaration, rather than at itsimplementation:
// sample header file void two_ints(int a = 1, int b = 4); // code of function in, say, two.cc void two_ints(int a, int b) { ... }It is an error to supply default arguments in both function definitions andfunction declarations. When applicable default arguments should be provided infunction declarations: when the function is used by other sources the compilercommonly reads the header file rather than the function definitionitself. Consequently the compiler has no way to determine the values ofdefault arguments if they are provided in the function definition.
0. InCNULL is often usedin the context of pointers. This difference is purely stylistic, though onethat is widely adopted. InC++NULL should be avoided (as it is amacro, and macros can --and therefore should-- easily be avoided inC++, see also section8.1.4). Instead0 can almost always beused.Almost always, but not always. AsC++ allows function overloading(cf. section2.5.4) the programmer might be confronted withan unexpected function selection in the situation shown in section2.5.4:
#include <stdio.h> void show(int val) { printf("Integer: %d\n", val); } void show(double val) { printf("Double: %lf\n", val); } void show(char const *val) { printf("String: %s\n", val); } int main() { show(12); show(3.1415); show("Hello World!\n"); }In this situation a programmer intending to callshow(char const *) mightcallshow(0). But this doesn't work, as 0 is interpreted asint and soshow(int) is called. But callingshow(NULL) doesn't work either, asC++ usually definesNULL as 0, rather than((void *)0). So,show(int) is called once again. To solve these kinds of problems the newC++ standard introduces the keywordnullptr representing the 0pointer. In the current example the programmer should callshow(nullptr)to avoid the selection of the wrong function. Thenullptr value can alsobe used to initialize pointer variables. E.g.,
int *ip = nullptr; // OK int value = nullptr; // error: value is no pointer
void func();
means that the argument list of the declared function is not prototyped: forfunctions using this prototype the compiler does not warn against callingfunc with any set of arguments. InC the keywordvoid is used whenit is the explicit intent to declare a function with no arguments at all, asin:
void func(void);
AsC++ enforces strict type checking, inC++ an empty parameterlist indicates thetotal absence of parameters. The keywordvoid isthus omitted.
__cplusplus: it is as if each source file were prefixed with thepreprocessor directive#define __cplusplus.We shall see examples of the usage of this symbol in the following sections.
As an example, the following code fragment declares a functionxmallocas aC function:
extern "C" void *xmalloc(int size);
This declaration is analogous to a declaration inC, except that theprototype is prefixed withextern "C".
A slightly different way to declareC functions is the following:
extern "C" { // C-declarations go in here }It is also possible to place preprocessor directives at the location ofthe declarations. E.g., aC header filemyheader.h which declaresC functions can be included in aC++ source file as follows:
extern "C" { #include <myheader.h> }Although these two approaches may be used, they are actually seldomencountered inC++ sources. A more frequently used method to declareexternalC functions is encountered in the next section.
__cplusplus and thepossibility to defineextern "C" functions offers the ability tocreate header files for bothC andC++. Such a header file might,e.g., declare a group of functions which are to be used in bothC andC++ programs.The setup of such a header file is as follows:
#ifdef __cplusplus extern "C" { #endif /* declaration of C-data and functions are inserted here. E.g., */ void *xmalloc(int size); #ifdef __cplusplus } #endifUsing this setup, a normalC header file is enclosed byextern "C"{ which occurs near the top of the file and by}, which occurs nearthe bottom of the file. The#ifdef directives test for the type of thecompilation:C orC++. The `standard'C header files, such asstdio.h, are built in this manner and are therefore usable for bothCandC++.
In additionC++ headers should supportinclude guards.InC++ it is usually undesirable to include the same header file twice inthe same source file. Such multiple inclusions can easily be avoided byincluding an#ifndef directive in the header file. For example:
#ifndef MYHEADER_H_ #define MYHEADER_H_ // declarations of the header file is inserted here, // using #ifdef __cplusplus etc. directives #endif
When this file is initially scanned by the preprocessor, the symbolMYHEADER_H_ is not yet defined. The#ifndef condition succeeds and alldeclarations are scanned. In addition, the symbolMYHEADER_H_ is defined.
When this file is scanned next while compiling the same source file,the symbolMYHEADER_H_ has been defined and consequently all informationbetween the#ifndef and#endif directives is skipped by the compiler.
In this context the symbol nameMYHEADER_H_ serves only forrecognition purposes. E.g., the name of the header file can be used for thispurpose, in capitals, with an underscore character instead of a dot.
Apart from all this, the custom has evolved to giveC header files theextension.h, and to giveC++ header filesno extension. Forexample, the standardiostreamscin, cout andcerr are availableafter including the header fileiostream, ratherthaniostream.h. In the Annotations this convention is usedwith the standardC++ header files, but not necessarily everywhere else.
There is more to be said about header files. Section7.11 providesan in-depth discussion of the preferred organization ofC++ header files.In addition, starting with theC++26 standardmodules are availableresulting in a somewhat more efficient way of handling declarations thanoffered by the traditional header files.
Currently, theC++ Annotations very briefly coversmodules (cf. section25).
for-statement, butalso all situations where a variable is only needed, say, half-way through thefunction.If considered appropriate,nested blocks can be used to localizeauxiliary variables. However, situations exist where local variables areconsidered appropriate inside nested statements. The just mentionedforstatement is of course a case in point, but local variables can also bedefined within the condition clauses ofif-else statements, withinselection clauses ofswitch statements and condition clauses ofwhilestatements. Variables thus defined are available to the fullstatement, including its nested statements. For example, consider thefollowingswitch statement:
#include <stdio.h> int main() { switch (int c = getchar()) { case 'a': case 'e': case 'i': case 'o': case 'u': printf("Saw vowel %c\n", c); break; case EOF: printf("Saw EOF\n"); break; case '0' ... '9': printf("Saw number character %c\n", c); break; default: printf("Saw other character, hex value 0x%2x\n", c); } } Note the location of the definition of the character `c': it isdefined in the expression part of theswitch statement. This impliesthat `c' is availableonly to theswitch statement itself,including its nested (sub)statements, but not outside the scope of theswitch.The same approach can be used withif andwhile statements: avariable that is defined in the condition clause of anif andwhilestatement is available in their nested statements. There are some caveats,though:
if orwhile statement,the value of the variable must be interpretable as either zero (false) ornon-zero (true). Usually this is no problem, but inC++objects (likeobjects of the typestd::string (cf. chapter5)) are oftenreturned by functions. Such objects may or may not be interpretable as numericvalues. If not (as is the case withstd::string objects), then suchvariables cannot be defined at the condition or expression clauses ofcondition- or repetition statements. The following example will thereforenot compile: if (std::string myString = getString()) // assume getString returns { // a std::string value // process myString }The above example requires additional clarification. Often a variable canprofitably be given local scope, but an extra check is required immediatelyfollowing its initialization. The initializationand the test cannotboth be combined in one expression. Insteadtwo nested statements arerequired. Consequently, the following example won't compile either:
if ((int c = getchar()) && strchr("aeiou", c)) printf("Saw a vowel\n");If such a situation occurs, either use two nestedif statements, orlocalize the definition ofint c using a nested compound statement:
if (int c = getchar()) // nested if-statements if (strchr("aeiou", c)) printf("Saw a vowel\n"); { // nested compound statement int c = getchar(); if (c && strchr("aeiou", c)) printf("Saw a vowel\n"); }TheC++26 standard introducedname-independent declarations. They'recovered in section ??.
typedef is still used inC++, but is not requiredanymore when definingunion,struct orenum definitions.This is illustrated in the following example: struct SomeStruct { int a; double d; char string[80]; };When astruct, union or other compound type is defined, the tag ofthis type can be used as type name (this isSomeStruct in the aboveexample):
SomeStruct what; what.d = 3.1415;
A definition of astruct Point is provided by the code fragment below.In this structure, twoint data fields and one functiondraw aredeclared.
struct Point // definition of a screen-dot { int x; // coordinates int y; // x/y void draw(); // drawing function };A similar structure could be part of a painting program and could, e.g.,represent a pixel. With respect to thisstruct it should be noted that:
draw mentioned in thestruct definition is ameredeclaration. The actual code of the function defining the actionsperformed by the function is found elsewhere (the concept of functions insidestructs is further discussed in section3.2).structPoint is equal to the size of itstwoints. A function declared inside the structure does not affect itssize. The compiler implements this behavior by allowing the functiondraw to be available only in the context of aPoint.Point structure could be used as follows:Point a; // two points on Point b; // the screen a.x = 0; // define first dot a.y = 10; // and draw it a.draw(); b = a; // copy a to b b.y = 20; // redefine y-coord b.draw(); // and draw it
As shown in the above example a function that is part of the structure maybe selected using the dot (.) (the arrow (->) operator is used whenpointers to objects are available). This is therefore identical to the waydata fields of structures are selected.
The idea behind this syntactic construction is that several types maycontainfunctions having identical names. E.g., a structure representing acircle might contain threeint values: two values for the coordinates ofthe center of the circle and one value for the radius. Analogously to thePoint structure, aCircle may now have a functiondraw to draw thecircle.
and andor, notdefined. C++ changed this for postfix expressions, assignment expressions(including compound assignments), and shift operators:variable++++ does not compile)).In the following examplesfirst is evaluated beforesecond, beforethird, beforefourth, whether they are single variables, parenthesizedexpressions, or function calls:
first.second fourth += third = second += first first << second << third << fourth first >> second >> third >> fourth
In addition, when overloading an operator, the function implementing theoverloaded operator is evaluated like the built-in operator it overloads, andnot in the way function calls are generally ordered.