C++ Introduction

333

description

C++ Introduction

Transcript of C++ Introduction

C++ LanguageThese tutorials explain the C++ language from its basics up to the newest features introduced by C++11. Chapters have a practical orientation, with example programs in all sections to start practicing what is being explained right away.

Introduction CompilersBasics of C++ Structure of a program Variables and types Constants Operators Basic Input/OutputProgram structure Control Structures Functions Overloads and templates Name visibilityCompound data types Arrays Character sequences Pointers Dynamic Memory Data structures Other data types

Classes Classes (I) Classes (II) Special members Friendship and inheritance Polymorphism

Other language features Type conversions Exceptions Preprocessor directives

C++ Standard Library Input/Output with files

CompilersThe essential tools needed to follow these tutorials are a computer and a compiler toolchain able to compile C++ code and build the programs to run on it.

C++ is a language that has evolved much over the years, and these tutorials explain many features added recently to the language. Therefore, in order to properly follow the tutorials, a recent compiler is needed. It shall support (even if only partially) the features introduced by the 2011 standard.

Many compiler vendors support the new features at different degrees. See the bottom of this page for some compilers that are known to support the features needed. Some of them are free!

If for some reason, you need to use some older compiler, you can access an older version of these tutorialshere(no longer updated).

What is a compiler?Computers understand only one language and that language consists of sets of instructions made of ones and zeros. This computer language is appropriately calledmachine language.

A single instruction to a computer could look like this:0000010011110

A particular computer's machine language program that allows a user to input two numbers, adds the two numbers together, and displays the total could include these machine code instructions:0000010011110

0000111110100

0001010011110

0001111010100

0010010111111

0010100000000

As you can imagine, programming a computer directly in machine language using only ones and zeros is very tedious and error prone. To make programming easier, high level languages have been developed. High level programs also make it easier for programmers to inspect and understand each other's programs easier.

This is a portion of code written in C++ that accomplishes the exact same purpose:1234567int a, b, sum; cin >> a;cin >> b; sum = a + b;cout = c) // evaluates to true, since (2*3 >= 6) is true(b+4 > a*c) // evaluates to false, since (3+4 > 2*6) is false((b=2) == a) // evaluates to true

Be careful! The assignment operator (operator=, with one equal sign) is not the same as the equality comparison operator (operator==, with two equal signs); the first one (=) assigns the value on the right-hand to the variable on its left, while the other (==) compares whether the values on both sides of the operator are equal. Therefore, in the last expression ((b=2) == a), we first assigned the value2toband then we compared it toa(that also stores the value 2), yieldingtrue.

Logical operators ( !, &&, || )The operator!is the C++ operator for the Boolean operation NOT. It has only one operand, to its right, and inverts it, producingfalseif its operand istrue, andtrueif its operand isfalse. Basically, it returns the opposite Boolean value of evaluating its operand. For example:1234!(5 == 5) // evaluates to false because the expression at its right (5 == 5) is true!(6 6) ) // evaluates to true ( true || false )

When using the logical operators, C++ only evaluates what is necessary from left to right to come up with the combined relational result, ignoring the rest. Therefore, in the last example ((5==5)||(3>6)), C++ evaluates first whether5==5istrue, and if so, it never checks whether3>6istrueor not. This is known asshort-circuit evaluation, and works like this for these operators:operatorshort-circuit

&&if the left-hand side expression isfalse, the combined result isfalse(the right-hand side expression is never evaluated).

||if the left-hand side expression istrue, the combined result istrue(the right-hand side expression is never evaluated).

This is mostly important when the right-hand expression has side effects, such as altering values:if ( (ib) ? a : b;

cout member access

3Prefix (unary)++ --prefix increment / decrementRight-to-left

~ !bitwise NOT / logical NOT

+ -unary prefix

& *reference / dereference

new deleteallocation / deallocation

sizeofparameter pack

(type)C-style type-casting

4Pointer-to-member.* ->*access pointerLeft-to-right

5Arithmetic: scaling* / %multiply, divide, moduloLeft-to-right

6Arithmetic: addition+ -addition, subtractionLeft-to-right

7Bitwise shift>shift left, shift rightLeft-to-right

8Relational< > =comparison operatorsLeft-to-right

9Equality== !=equality / inequalityLeft-to-right

10And&bitwise ANDLeft-to-right

11Exclusive or^bitwise XORLeft-to-right

12Inclusive or|bitwise ORLeft-to-right

13Conjunction&&logical ANDLeft-to-right

14Disjunction||logical ORLeft-to-right

15Assignment-level expressions= *= /= %= += -=>>= > myint;

This declares astringwith initialized to a value of"1204", and a variable of typeint. Then, the third line uses this variable to extract from astringstreamconstructed from the string. This piece of code stores the numerical value1204in the variable calledmyint.123456789101112131415161718192021// stringstreams#include #include #include using namespace std;

int main (){ string mystr; float price=0; int quantity=0;

cout > price; cout > quantity; cout 0; n--) { if (n==5) continue; cout ):12345678910111213141516171819202122232425262728293031// pointers to structures#include #include #include using namespace std;

struct movies_t { string title; int year;};

int main (){ string mystr;

movies_t amovie; movies_t * pmovie; pmovie = &amovie;

cout title); cout > pmovie->year;

cout titleand(*pmovie).titleare valid, and both access the membertitleof the data structure pointed by a pointer calledpmovie. It is definitely something different than:*pmovie.title

which is rather equivalent to:*(pmovie.title)

This would access the value pointed by a hypothetical pointer member calledtitleof the structure objectpmovie(which is not the case, sincetitleis not a pointer type). The following panel summarizes possible combinations of the operators for pointers and for structure members:ExpressionWhat is evaluatedEquivalent

a.bMemberbof objecta

a->bMemberbof object pointed to bya(*a).b

*a.bValue pointed to by memberbof objecta*(a.b)

Nesting structuresStructures can also be nested in such a way that an element of a structure is itself another structure:123456789101112struct movies_t { string title; int year;};

struct friends_t { string name; string email; movies_t favorite_movie;} charlie, maria;

friends_t * pfriends = &charlie;

After the previous declarations, all of the following expressions would be valid:1234charlie.namemaria.favorite_movie.titlecharlie.favorite_movie.yearpfriends->favorite_movie.year

(where, by the way, the last two expressions refer to the same member).Other data typesType aliases (typedef / using)A type alias is a different name by which a type can be identified. In C++, any valid type can be aliased so that it can be referred to with a different identifier.

In C++, there are two syntaxes for creating such type aliases: The first, inherited from the C language, uses thetypedefkeyword:

typedef existing_type new_type_name ;

whereexisting_typeis any type, either fundamental or compound, andnew_type_nameis an identifier with the new name given to the type.

For example:1234typedef char C;typedef unsigned int WORD;typedef char * pChar;typedef char field [50];

This defines four type aliases:C,WORD,pChar, andfieldaschar,unsigned int,char*andchar[50], respectively. Once these aliases are defined, they can be used in any declaration just like any other valid type:1234C mychar, anotherchar, *ptc1;WORD myword;pChar ptc2;field name;

More recently, a second syntax to define type aliases was introduced in the C++ language:using new_type_name = existing_type ;

For example, the same type aliases as above could be defined as:1234using C = char;using WORD = unsigned int;using pChar = char *;using field = char [50];

Both aliases defined withtypedefand aliases defined withusingare semantically equivalent. The only difference being thattypedefhas certain limitations in the realm of templates thatusinghas not. Therefore,usingis more generic, althoughtypedefhas a longer history and is probably more common in existing code.

Note that neithertypedefnorusingcreate new distinct data types. They only create synonyms of existing types. That means that the type ofmywordabove, declared with typeWORD, can as well be considered of typeunsigned int; it does not really matter, since both are actually referring to the same type.

Type aliases can be used to reduce the length of long or confusing type names, but they are most useful as tools to abstract programs from the underlying types they use. For example, by using an alias ofintto refer to a particular kind of parameter instead of usingintdirectly, it allows for the type to be easily replaced bylong(or some other type) in a later version, without having to change every instance where it is used.

UnionsUnions allow one portion of memory to be accessed as different data types. Its declaration and use is similar to the one of structures, but its functionality is totally different:union type_name { member_type1 member_name1; member_type2 member_name2; member_type3 member_name3; . .} object_names;

This creates a new union type, identified bytype_name, in which all its member elements occupy the same physical space in memory. The size of this type is the one of the largest member element. For example:12345union mytypes_t { char c; int i; float f;} mytypes;

declares an object (mytypes) with three members:123mytypes.cmytypes.imytypes.f

Each of these members is of a different data type. But since all of them are referring to the same location in memory, the modification of one of the members will affect the value of all of them. It is not possible to store different values in them in a way that each is independent of the others.

One of the uses of a union is to be able to access a value either in its entirety or as an array or structure of smaller elements. For example:12345678union mix_t { int l; struct { short hi; short lo; } s; char c[4];} mix;

If we assume that the system where this program runs has aninttype with a size of 4 bytes, and ashorttype of 2 bytes, the union defined above allows the access to the same group of 4 bytes:mix.l,mix.sandmix.c, and which we can use according to how we want to access these bytes: as if they were a single value of typeint, or as if they were two values of typeshort, or as an array ofcharelements, respectively. The example mixes types, arrays, and structures in the union to demonstrate different ways to access the data. For a little-endian system, this union could be represented as:

The exact alignment and order of the members of a union in memory depends on the system, with the possibility of creating portability issues.

Anonymous unionsUnions can also be declared with no type name or object name. In this case, they become anonymous unions, and its members are directly accessible by their member names. For example, look at the differences between these two structure declarations:structure with regular unionstructure with anonymous union

struct { char title[50]; char author[50]; union { float dollars; int yen; } price;} book;struct { char title[50]; char author[50]; union { float dollars; int yen; };} book;

The only difference between the two pieces of code is that in the first one, the union has a name (price), while in the second it has not. This affects the way to access membersdollarsandyenof an object of this type. For an object of the first type (a regular union), it would be:12book.price.dollarsbook.price.yen

whereas for an object of the second type (an anonymous union), it would be:12book.dollarsbook.yen

Again, remember that because it is a union (not a structure), the membersdollarsandyenactually share the same memory location, so they cannot be used to store two different values simultaneously. Thepricecan be set indollarsor inyen, but not in both simultaneously.

Enumerated types (enum)Enumerated typesare types that are defined with a set of custom identifiers, known asenumerators, as possible values. Objects of theseenumerated typescan take any of these enumerators as value.

Their syntax is:enum type_name { value1, value2, value3, . .} object_names;

This creates the typetype_name, which can take any ofvalue1,value2,value3, ... as value. Objects (variables) of this type can directly be instantiated asobject_names.

For example, a new type of variable calledcolors_tcould be defined to store colors with the following declaration:enum colors_t {black, blue, green, cyan, red, purple, yellow, white};

Notice that this declaration includes no other type, neither fundamental nor compound, in its definition. To say it another way, somehow, this creates a whole new data type from scratch without basing it on any other existing type. The possible values that variables of this new typecolor_tmay take are the enumerators listed within braces. For example, once thecolors_tenumerated type is declared, the following expressions will be valid:1234colors_t mycolor; mycolor = blue;if (mycolor == green) mycolor = red;

Values ofenumerated typesdeclared withenumare implicitly convertible to the integer typeint, and vice versa. In fact, the elements of such anenumare always assigned an integer numerical equivalent internally, of which they become an alias. If it is not specified otherwise, the integer value equivalent to the first possible value is0, the equivalent to the second is1, to the third is2, and so on... Therefore, in the data typecolors_tdefined above,blackwould be equivalent to0,bluewould be equivalent to1,greento2, and so on...

A specific integer value can be specified for any of the possible values in the enumerated type. And if the constant value that follows it is itself not given its own value, it is automatically assumed to be the same value plus one. For example:123enum months_t { january=1, february, march, april, may, june, july, august, september, october, november, december} y2k;

In this case, the variabley2kof the enumerated typemonths_tcan contain any of the 12 possible values that go fromjanuarytodecemberand that are equivalent to the values between1and12(not between0and11, sincejanuaryhas been made equal to1).

Because enumerated types declared withenumare implicitly convertible toint, and each of the enumerator values is actually of typeint, there is no way to distinguish1fromjanuary- they are the exact same value of the same type. The reasons for this are historical and are inheritance of the C language.

Enumerated types with enum classBut, in C++, it is possible to create realenumtypes that are neither implicitly convertible tointand that neither have enumerator values of typeint, but of theenumtype itself, thus preserving type safety. They are declared withenum class(orenum struct) instead of justenum:enum class Colors {black, blue, green, cyan, red, purple, yellow, white};

Each of the enumerator values of anenum classtype needs to be scoped into its type (this is actually also possible withenumtypes, but it is only optional). For example:1234Colors mycolor; mycolor = Colors::blue;if (mycolor == Colors::green) mycolor = Colors::red;

Enumerated types declared withenum classalso have more control over their underlying type; it may be any integral data type, such aschar,shortorunsigned int, which essentially serves to determine the size of the type. This is specified by a colon and the underlying type following the enumerated type. For example:enum class EyeColor : char {blue, green, brown};

Here,Eyecoloris a distinct type with the same size of achar(1 byte). Classes (I)Classesare an expanded concept ofdata structures: like data structures, they can contain data members, but they can also contain functions as members.

Anobjectis an instantiation of a class. In terms of variables, a class would be the type, and an object would be the variable.

Classes are defined using either keywordclassor keywordstruct, with the following syntax:class class_name { access_specifier_1: member1; access_specifier_2: member2; ...} object_names;

Whereclass_nameis a valid identifier for the class,object_namesis an optional list of names for objects of this class. The body of the declaration can containmembers, which can either be data or function declarations, and optionallyaccess specifiers.

Classes have the same format as plaindata structures, except that they can also include functions and have these new things calledaccess specifiers. Anaccess specifieris one of the following three keywords:private,publicorprotected. These specifiers modify the access rights for the members that follow them: privatemembers of a class are accessible only from within other members of the same class (or from their"friends"). protectedmembers are accessible from other members of the same class (or from their"friends"), but also from members of their derived classes. Finally,publicmembers are accessible from anywhere where the object is visible.

By default, all members of a class declared with theclasskeyword have private access for all its members. Therefore, any member that is declared before any otheraccess specifierhas private access automatically. For example:123456class Rectangle { int width, height; public: void set_values (int,int); int area (void);} rect;

Declares a class (i.e., a type) calledRectangleand an object (i.e., a variable) of this class, calledrect. This class contains four members: two data members of typeint(memberwidthand memberheight) withprivate access(because private is the default access level) and two member functions withpublic access: the functionsset_valuesandarea, of which for now we have only included their declaration, but not their definition.

Notice the difference between theclass nameand theobject name: In the previous example,Rectanglewas theclass name(i.e., the type), whereasrectwas an object of typeRectangle. It is the same relationshipintandahave in the following declaration:int a;

whereintis the type name (the class) andais the variable name (the object).

After the declarations ofRectangleandrect, any of the public members of objectrectcan be accessed as if they were normal functions or normal variables, by simply inserting a dot (.) betweenobject nameandmember name. This follows the same syntax as accessing the members of plain data structures. For example:12rect.set_values (3,4);myarea = rect.area();

The only members ofrectthat cannot be accessed from outside the class arewidthandheight, since they have private access and they can only be referred to from within other members of that same class.

Here is the complete example of class Rectangle:12345678910111213141516171819202122// classes example#include using namespace std;

class Rectangle { int width, height; public: void set_values (int,int); int area() {return width*height;}};

void Rectangle::set_values (int x, int y) { width = x; height = y;}

int main () { Rectangle rect; rect.set_values (3,4); cout