Dr.

Dragan Mili ev
Ass. Professor, University of Belgrade dmilicev@rcub.bg.ac.yu, www.rcub.bg.ac.yu/~dmilicev

The C++ Programming Language
Introductory Course 
Covers basic concepts and elements of C++  Requires knowledge of fundamental concepts of objectoriented and procedural programming  Does not require knowledge of C
June 2003 Copyright (C) 2003 by Dragan Mili ev 1

Outline
Part I: Part II: Part III: Part IV: Part V: Part VI: Introduction General Issues Procedural Elements Classes Derived Classes and Polymorphism Conclusions

June 2003

Copyright (C) 2003 by Dragan Mili ev

2

Part I: Introduction
About this Course Getting Started

June 2003

Copyright (C) 2003 by Dragan Mili ev

3

Chapter 1: About this Course
Subject and Objectives Prerequisites Resources

June 2003

Copyright (C) 2003 by Dragan Mili ev

4

Subject and Objectives Subject:     Basic concepts of the C++ programming language Implementation of procedural and OO concepts in C++ Style guidelines for programming in C++ General applicability: not oriented to any library. and write C++ programs Objectives:   June 2003 Copyright (C) 2003 by Dragan Mili ev 5/209 . understand. or tool Get familiar with the basic concepts of C++ Get ready to read. framework.

objects. condition. loop Subprogram (procedure and function). argument (formal and actual). expression. constructors/destructors. statement. pointer/reference Declaration. invocation. recursion Understanding of fundamental concepts of the object-oriented programming paradigm:     Classes. substitution) and polymorphism Copyright (C) 2003 by Dragan Mili ev 6/209 June 2003 . and references to objects Attributes and structural relationships Operations. and encapsulation Inheritance (generalization/specialization.Prerequisites Understanding of fundamental concepts of the procedural programming paradigm:    Type and variable.

and design patterns June 2003 Copyright (C) 2003 by Dragan Mili ev 7/209 . The C++ Programming Language. Stroustrup.yu/~dmilicev Other books on OO programming.bg. Stroustrup. Ellis. C++ and other programming languages.ac..rcub. B. 2nd ed. Addison-Wesley. Addison-Wesley. 1993 M. 1990 Discussion with Dr.yu www.bg. The Annotated C++ Reference Manual.Resources Books on OO programming and C++:   B.ac. Mili ev: dmilicev@rcub. A.

Chapter 2: Getting Started About C++ C/C++ Design Principles A Simple C++ Program June 2003 Copyright (C) 2003 by Dragan Mili ev 8 .

C++ is a language of a new generation and of different paradigm than C! The difference between C and C++ is much bigger (conceptual) than between C++ and Java. for example C++ supports all fundamental OO concepts. object-oriented. not prevents from making bad OO or procedural programs C++ is a means of expressing OO design of software June 2003 Copyright (C) 2003 by Dragan Mili ev 9/209 .About C++ C++ is a standard. common-purpose programming language C++ is vertically compatible with C: all C programs can be compiled with C++ compilers However. but also allows non-OO parts or entire programs C++ is a tool that helps to make good OO programs.

consequently. strong.C/C++ Design Principles C++ is vertically compatible with C: all C programs can be compiled with C++ compilers Efficiency of implementation: the compiled code has almost the same efficiency as the equivalent hand-written assembly code Extensive compile-time checking No runtime checking Static typing. the sizes of the built-in types are not standard June 2003 Copyright (C) 2003 by Dragan Mili ev 10/209 . but not exclusive typing (conversions are allowed) Uniform treatment of built-in (primitive) and user-defined (classes) types of objects Alignment of the sizes of the built-in types to the machine architecture.

increments them independently.A Simple C++ Program Task: Write a class that abstracts a counter that can be initialized to the given value. and writes their values at the standard output. incremented.counter : int 11/209 4 3 5 Counter June 2003 inc() val()? Copyright (C) 2003 by Dragan Mili ev . create(3) inc() Counter + Counter(int) + inc() + val() : int . and asked for the current value. Write a program that creates several counters.

Start of the section of private class members Counter::Counter (int initVal) { End of definition of class Counter counter = initVal.h> Comment: from // to end of line standard input/output operations Start of definition of class Counter class Counter { Start of the section of public class members public: Counter (int initVal). without arguments and with an integer result }. Definition of the constructor of class Counter } Access to the member of the object being constructed Start of the method definition: aAssignment expression as a statement compound End of the method definition (block) statement (block) June 2003 Copyright (C) 2003 by Dragan Mili ev 12/209 Declaration of an integer attribute (data member) . Declaration of an operation (member function) without arguments and with no result private: Declaration of an operation (member function) int counter. int val(). Declaration of a constructor with an integer argument void inc ().A Simple C++ Program // A simple C++ program Include declarations of librarian elements for #include <iostream.

with no arguments and an return counter. inc() of pointer the object of Counter cout<<c1->val()<<³ ³<<c2->val(). result } Expression as a statement int Counter::val () { Definition of the operation val(). constructor output delete c1. End of block as the body of functionof the invocationmain Writing the result main() (end of to delete c2. with no arguments and no counter = counter + 1. compulsory of the member function Invocation global function main() Declaration a local variable c1 as a c1->inc(). c1->inc(). Access to the data member of the object of integer result } } which the operation is invoked Return statement: returns the result of the expression void main () { as the result of of a operation invocation function Definition the global (nonmember) Counter* c1 = new Counter(0). member of the class Counter. anobject pointed by c1 of Creation ofto new. Counter. member of continued: void Counter::inc () { the class Counter.objectan actual argumentstandard val() of that abstracts the of An with the object pointed to by c1 cout<<c1->val()<<³ ³<<c2->val(). anonymous object a Invocation of the member function c1->inc().A Simple C++ Program // A simple C++ program. Definition of the operation inc(). Linking c1 to the anonymous object The program execution starts from a Counter* c2 = new Counter(3). program) standard output Destruction of the anonymous object pointed to by c1 June 2003 Copyright (C) 2003 by Dragan Mili ev 13/209 . c2->inc().

Part II: General Issues Lexical Elements Types and Conversions Built-in Types Declarations and Scopes Object Lifetimes Program Structure June 2003 Copyright (C) 2003 by Dragan Mili ev 14 .

Chapter 3: Lexical Elements Tokens Comments Identifiers Literals June 2003 Copyright (C) 2003 by Dragan Mili ev 15 .

as in all traditional programming languages Tokens: identifiers. new lines. and if (a<c++) a=3. new pages White spaces separate tokens and do not nave any other meaning for the compiler. literals. Styling conventions: use the traditional indentation style to improve readability. tabs. operators and separators June 2003 Copyright (C) 2003 by Dragan Mili ev 16/209 . keywords. these are equivalent: if (a< c++) a = 3.Tokens C++ is case-sensitive White spaces: blanks.

Comments Two kinds of comments:   from // to the end of line from /* to */ (may spread over many lines) // This is a single-line comment /* This is a multi-line comment */ Comments are considered white spaces (separate tokens) //. /*. and */ do not have any special meaning within a comment that starts with // // and /* do not have any special meaning within a comment that starts with /* June 2003 Copyright (C) 2003 by Dragan Mili ev 17/209 .

Identifiers Identifiers are arrays of alphanumerical characters of arbitrary length. starting with a letter from the English alphabet. all characters are significant Underscore (_) is treated as a letter Identifiers are case-sensitive Styles of writing identifiers:   old-fashioned C-style: my_bank_account modern OO style: myBankAccount names of classes and interfaces are capitalized names of other elements are not Copyright (C) 2003 by Dragan Mili ev 18/209 OO style guidelines:   June 2003 .

E4f // 2. type double . type (signed) long int 0x1afUL // hexadecimal.0E4.2 // 0.Literals Integer literals: 10 // decimal.0 // 0. number eight of type int 0x10 // hexadecimal. number sixteen of type int 120034L // decimal. type double . number ten of type int 010 // octal.2.4e-1 // 0. type float Character literals: µa¶ // character µa¶ of type char µ\n¶ // nonprintable character µnew line¶ µ\t¶ // nonprintable character µtab¶ µ\\¶ // character µ\¶ µ\0¶ // nonprintable character with code 0 June 2003 Copyright (C) 2003 by Dragan Mili ev 19/209 . type double .2.0. type unsigned long int Floating-point literals: 1.2 // 1. type double 2.4E-1.

Literals String literals: ³This is a string literal´ ³Enter \´Yes\´ or \´No\´´ ³This literal ends with a new line\n´ For each string literal in the program. terminated with an additional character with the code zero (the \0 character): ³Hello´ // This string literal has 6 characters! This is the traditional C convention on which the librarian functions that deal with strings rely ( null-terminated strings ) String-literals are of type char[] (array of characters) June 2003 Copyright (C) 2003 by Dragan Mili ev 20/209 . the compiler allocates a space in the compiled code and initializes it with the given string of characters.

Chapter 4: Types and Conversions Objects and Types Type Classification Type Conversions June 2003 Copyright (C) 2003 by Dragan Mili ev 21 .

through conversions June 2003 Copyright (C) 2003 by Dragan Mili ev 22/209 . and not at runtime (except for polymorphism) Objects of different types can be mixed in a controlled way. The types are determined and checked at compile time. objects have their lifetime In the broader context of OO programming. but not a reference An object is something that lives in the computer s data memory at runtime and is generally modifiable (not all objects are modifiable). the term object refers to an instance of a built-in or user-defined type. the term object has a broader meaning an instance of a built-in type or class Objects have their precisely defined types.Objects and Types In C++. in the narrower context of the C++ language. the term object has a narrower meaning (an instance of a class).

arrays. enumerations Derived types: arrays. floating-point numbers. integers. functions Built-in types: characters. references. enumerations. unions. functions User-defined types: structures. pointers. constants. structures. classes. pointer to class members. classes Classification II:   June 2003 Copyright (C) 2003 by Dragan Mili ev 23/209 . pointer to class members. floating-point numbers. references.Types Classification Classification I:   Fundamental types: characters. integers. pointers. constants. unions.

while. reference. do. the compiler simply treats and uses the same element in a different manner. with a defined value or state operators for built-in types expect operands of defined types some statements use expressions with the results of defined types (if. for.Type Conversions Each time when an object. conversion takes place Conversion may have different semantics. according to its target type a new temporary object is created out from the offered object. switch) an object or reference of one type is initialized with an object or reference of another type Copyright (C) 2003 by Dragan Mili ev 24/209 The cases when a conversion may take place:    June 2003 . or function of one type is expected and one of another type is used. or function created at runtime as a result of the conversion. depending on the specific case:   there is no new object. reference.

the compiler may convert implicitly explicitly requested by the programmer by the cast operator: (type)expression Copyright (C) 2003 by Dragan Mili ev 25/209 A conversion may be:   June 2003 . or a reference/pointer to a derived class can be converted to a reference/pointer to a base class (support for the substitution rule) the user (programmer. for example. user-defined types): the conversion among objects of classes implicitly performed by the compiler: when a conversion is needed and it is defined and allowed. char can be converted to int. built-in conversions among built-in types).Type Conversions A conversion may be defined by:   the language (standard.

(charpint) Base* pB = new Derived. float f = 5. Implicit.cast (doublepfloat. superfluous) int a = 5. built-in conversion (intpdouble) float h = a+d-1. June 2003 Copyright (C) 2003 by Dragan Mili ev 26/209 .5e-3. built-in double) (intp conversion .6. built-in conversion . Implicit.6.Implicit.Type Conversions int i = µa¶. Implicit. built-in conversion (charpint) conversion Implicit. built-in conversion (Derived*pBase*) upcasting Explicit. double d = 1. built-in conversion (doublepfloat) int b = a+¶0¶. Implicit. Not allowed implicitly. Derived* pD = (Derived*)pB. built-in (doublepfloat) Explicit. float g = (float)5. built-in conversion Implicit. built-in conversion .(Base*pDerived*) downcasting. because it is not type safe the compiler cannot guarantee that the pointer to Base actually points to a Derived.

Chapter 5: Built-in Types Character Types Boolean Type Integer Types Floating-Point Types Enumerations Pointers Arrays June 2003 Copyright (C) 2003 by Dragan Mili ev 27 .

. // conversions char->int->char . i++) { char c2 = c1+i. which have the same memory size as char. // character µ0¶ char c2 = µ\0¶ // character with code 0 An object of type char can be converted into an int with the value of the code of that character in the underlying character set (usually. // character with code 0. but treated differently when converted into int:   signed char: the integer value may be negative unsigned char: the integer value is always non-negative Copyright (C) 2003 by Dragan Mili ev 28/209 June 2003 . i<10.Character Types The type char represents characters: char c1 = µ0¶. conversion int->char char c1 = µ0¶. } Variants of char.. for (int i=0. but not necessarily ASCII): char c = 0.

and true to 1 An integer object may be implicitly converted into a bool: 0 is converted to false..Boolean Type Newer version of C++ allow a Boolean type bool The objects of bool may have one of two symbolic values: false and true A Boolean object may be implicitly converted into an integer: false is converted to 0. and any non-zero value to true bool flag = false.... June 2003 Copyright (C) 2003 by Dragan Mili ev 29/209 . flag = true. . ... if (flag) .

// unsigned long int June 2003 Copyright (C) 2003 by Dragan Mili ev 30/209 . not compilation error) Examples: short si = 127. // signed short int unsigned long ul = 123456UL.Integer Types Integer types:    int: the basic integer type of the size of one machine word (most efficient) short int (or short for short): integer of size less than or equal to the size of int long int (or long for short): integer of size greater than or equal to the size of int signed (default): values may be negative unsigned: values are always non-negative Variants of the same size as the primary type:   Conversions to smaller-sized types or from signed to unsigned and vice versa may lose information (warning.

long double dl = 1. double d = 1.5e-4. June 2003 Copyright (C) 2003 by Dragan Mili ev 31/209 .14.3. not compilation error) Examples: float pi = 3.Floating-Point Types Types for floating-point rational numbers:    double: default floating-point type float: floating-point of size less than or equal to the size of double long double: floating-point of size greater than or equal to the size of double Conversions to smaller-sized types may lose information or precision (warning.

Status s1 = initiated.. enum Status { initiated. June 2003 Copyright (C) 2003 by Dragan Mili ev 32/209 . true }. canceled. committed. if (s1==committed) . CANCEL }. NO. . failed }... suspended. enum Reply { YES.. Its instances may take only the values from the set Examples: enum Bool { false.Enumerations Enumeration is a type that defines a finite set of discrete symbolic values.

Enumerations There is a standard (built-in) conversion from an enumeration value to an int. suspended. failed = committed+4 }.... canceled. . // conversion Status->int.. suspended. // failed = 7 The opposite conversion (intpenum) may not be implicit: Status s = 3. failed }. if (s==4) . // i gets the value 1 Status s = canceled. // Error! June 2003 Copyright (C) 2003 by Dragan Mili ev 33/209 . starting from 0: enum Status { initiated. canceled = 5. // evaluates to true if s==failed The default ordering can be changed: enum Status { initiated = 1. committed. //suspended = 2 committed. int i = suspended. resulting in the value of the order number of the symbol in the set.

subtraction. it is difficult to find those occurrences of the type that are not really the intentional usage of built-in integer types and replace them Copyright (C) 2003 by Dragan Mili ev 34/209 June 2003 . because:    the program is more difficult to understand. multiplication.Enumerations Enumerations should be used whenever there is a need for a data type that abstracts a concept from the problem domain and its instances take values from a finite discrete set of symbolic values It is not wise to use a built-in integer type instead of an enumeration in that case.) the program is less flexible: if there is a need to change the decision about the implementation of the abstract type. etc. because the abstract type is mixed with the built-in integer type the values of the abstract type should not take part in arithmetic operations (addition.

pointers are implemented as memory cells that carry values of the addresses of pointed objects in memory. except in special cases of debugging pointers A pointer realizes a unidirectional link to an object. this is a matter of implementation and the concrete value of a pointer should not be considered. and the programmer is responsible for the pointer s validity Copyright (C) 2003 by Dragan Mili ev 35/209 . pointers are not safe against some severe problems. there is no additional information about the linkage of the pointer and the pointed object and no runtime checking of pointer validity. consequently. however.Pointers aPointer anObject June 2003 A pointer is an object that points to another object In C++.

// &x is of type T* . // *p is of type T and refers to x June 2003 Copyright (C) 2003 by Dragan Mili ev 36/209 ... T* p = &x..Pointers Tx T* p If a pointer p points to an object x.*p. but a pointer to T . then the operation *p results in the object x (pointer dereferencing) The operation &x results in a pointer value that points to the object x (address operation) Pointers are derived types: there is no a pointer (just like this).. The type pointer to T is denoted with T*: T x.

int* pi = &i. j=0.inc(). pi=&j. // the same June 2003 Copyright (C) 2003 by Dragan Mili ev 37/209 . *pi=2. p->inc().Pointers int i=0. 4 j=*pi. 2 3 5 1 int 2 0 int* pi i 2 0 j Counter* p = new Counter(4). // call inc() of *P (*p).

int** ppi. 3 2 int* pi=&i. // Evaluated: *(*ppi) 7 *ppi=&j. j=0. // ³pointer to. // Compilation error: // int* cannot be converted to int** int 2 1 0 int** ppi int* pi i 0 June 2003 Copyright (C) 2003 by Dragan Mili ev 6 j 38/209 . 5 *pi=1.int".Pointers Pointers are objects that point to objects. including other pointers: 1 int i=0. ppi=&i. 4 ppi=&pi.pointer to . **ppi=2.

Copyright (C) 2003 by Dragan Mili ev 39/209 June 2003 .... they are used in low-level programming when accessing raw data in computer memory or hardware registers Counter* c = new Counter(7)... not necessarily the binary value of the pointer s implementation (although often so). void* pointers are not used in OO programs because they are not type-safe. void* p = c. if(p!=0). p->inc(). // Compilation error: *p is not a Counter! A pointer can point to nothing a null pointer with the symbolic value 0. There are no objects of type void. The value 0 is a symbolic value. A pointer can be:   initialized or assigned the null value: int* p=0. checked against the null value: if(p==0).. p=0. only pointers of type void*.Pointers A pointer of type void can point to an object of any type (typeless pointer). .

Here are some most often problems Invalid pointer  Cause: dereferencing a pointer with an invalid value (points to an invalid object. // Pointer has undefined default value p->inc(). // No default initial value! p->inc(). // Possible runtime error or exception! June 2003 Copyright (C) 2003 by Dragan Mili ev 40/209 . its value is an invalid or corrupted address).Pointers C/C++ pointers are very unsafe and may cause severe bugs. neither a pointer nor its pointed object are checked against validity at runtime: Counter* p. // Possible runtime error!  Effect:  a possible (but not always) runtime error or exception (memory access violation or program blockage)  a bug (invalid result of an operation)  Typical cases of occurrences:  uninitialized pointer: Counter* p.

5 a[i]=i. // Irregular access to nonexisting a[5] p->inc().Pointers  corrupted pointer: int a[5]. i<=5.. // p is probably allocated behind the array for (int i = 0.4] Counter* p = new Counter(2).. i++) // a loop i:=0. // array of 5 integers in range [0. // p is probably corrupted!  Cure:     careful programming always initialize pointers check indices against array boundaries compilers sometimes warn you to these problems June 2003 Copyright (C) 2003 by Dragan Mili ev 41/209 .

.Pointers Null-pointer dereferencing  Cause: dereferencing a pointer with a null value.. // May return 0 p->inc().). typically as a result of a function: Counter* getCounter(.. // Possible runtime error! June 2003 Copyright (C) 2003 by Dragan Mili ev 42/209 . // function that returns a ptr . // May return 0 p->inc(). new returns null: Counter* p = new Counter(7)..).. // Runtime error (probably hardware exception)!  Effect:  a runtime error on almost all platforms (a memory-access-violation hardware exception in most cases)  Typical cases of occurrences:  non-checked pointer value. a pointer is not checked against null value at runtime: Counter* p = 0.. p->inc(). Counter* p = getCounter(. // Possible runtime error!  non-checked result of new. when there is no free memory.

.p->.Pointers  Cure:  always check the pointer as a result of a function or new: Counter* p = getCounter(.....). if (p!=0) .*p... June 2003 Copyright (C) 2003 by Dragan Mili ev 43/209 . if (p!=0) p->inc()... // Or: Counter* p = new Counter(7)..  never believe in pointers always check them before dereferencing (very conservative) : if (p!=0) .

.Pointers Dangling pointer:  Cause: dereferencing a pointer that points to a destroyed object... // In yet another context: . // Bug: *p does not exist any more!  Effect:  a bug due to the access of invalid objects  sometimes a runtime error. .. ... // p and q don¶t change their values even to 0 ... p->inc(). or .*q. delete p.. or exception. because the memory space of the destroyed object may have been allocated by other system data  Typical cases of occurrences:  invalid use of objects and pointers: Counter* p = new Counter(3). blockage. // In another context: Counter* q = p... // In yet another context: delete p... June 2003 Copyright (C) 2003 by Dragan Mili ev 44/209 .. the pointer is not notified on destruction of the pointed object: Counter* p = new Counter(5).q->.

automatic integer ...Pointers  returning pointers to automatic (local) objects placed on the stack from functions: int* f() { int x = 5. // a local. // x dies on function return } .. return &x. // p is a dangling pointer!  Cure:  Careful programming  Compilers often warn you to dangling pointers.. especially as return values of functions June 2003 Copyright (C) 2003 by Dragan Mili ev 45/209 . int* p = f().

.n-1]: a[2] = 5. T n-2 T n-1 An array is an object that represents an ordered. but an array of objects of type T . The type an array of Ts is denoted with T[]: int a[100]. bounded collection of objects with a fixed size determined at the time of its creation Arrays are derived types: there is no an array (just like this). // An array of 100 ints The indices of an array are always in the range [0..... // access to the third element a[50] = a[0]+a[99]. .Arrays T 0 T 1 T 2 . June 2003 Copyright (C) 2003 by Dragan Mili ev 46/209 .

// (m[3])[5] is its 6th integer element June 2003 Copyright (C) 2003 by Dragan Mili ev 47/209 . // m[3] is the 4th element of m. runtime errors are possible due to range errors (corruption of other data or runtime exceptions due to memory access violations) An element of an array may be any object. even another array (multidimensional arrays): int m[5][7].Arrays There is no runtime range-checking of indices. Therefore. // evaluated as (m[3])[5]. // a 5 x 7 matrix m[3][5] = 2. // it is an array of 7 ints.

arrays are not passed to functions by value (as entire packages of elements). arrays and pointers are tightly coupled by the following rules June 2003 Copyright (C) 2003 by Dragan Mili ev 48/209 . Consequently. apart from the index. to generate the code to access an element of an array. C/C++ arrays are used in operations with as little information about them as possible.Arrays Due to its orientation to efficiency. but by a pointer to their beginning. the invoked function does not have an implicit information about the array size they must be provided by the program semantics! Therefore. which is determined by its type This information can be deduced from a pointer to the first element of the array. For example. the compiler needs:   the starting address of the array the size of an element.

T T i p June 2003 p+i Copyright (C) 2003 by Dragan Mili ev 49/209 .. the result of addition p+i (where i is an integer) is a value of a pointer that points to the element of the same array. it is implicitly converted into a pointer (of type T*) that points to the array s first element: T[] p T* Rule #2: For a pointer (of type T*) and an integer. i places ahead: T T T . if a pointer p points to an element of an array..Arrays Rule #1: Whenever an array (of type T[]) is used in an operation (except for &). the operations of additions and subtractions are defined.

but simply the code that sums up the value of the pointer and the value of the integer multiplied by the size of an element.Arrays Rule #2 (continued): The result is defined provided that   the pointer points to an element of an array and the resulting pointer points to an element of the same array. If the rules are not satisfied. June 2003 Copyright (C) 2003 by Dragan Mili ev 50/209 . there is no compilation warning or error. but the result will be undefined (a silent bug due to invalid or corrupted data or a runtime exception due to memory access violation). The similar holds for subtraction of an integer from a pointer (the result is a pointer i places backward) or for subtraction of two pointers that point to elements of the same array (the result is an integer). or one element behind (not allowed to dereference) These rules are not checked at runtime: the compiler does not generate the code for checking against these rules.

a[2]=1. By Rule #2. // p points to a[0]. and the result of the pointer is added pointer by added with 1 and the result p=p+1. the resulting pointer is dereferenced by *(p+3).Arrays a[2]|*(a+2) by Rule treated as *(a+i) by Rule #3: The expression a[i] is #3 in *(a+2). a is converted into a pointer to its first element definition of type int* by Rule #1 The same as: = a. and the int a[10]. and the result of Consequences:  the treatment of array indexing operation: the resulting pointer is dereferenced by *(a+2). because a is converted into &a the pointer is added with 2 by Rule #2. The result of p-1 is a pointer that points one element in front of the one pointed to by p June 2003 Copyright (C) 2003 by Dragan Mili ev 51/209 . points to the next element in (p+3) is a pointer that points to a[3] the array *(p+2)=1. and the p[-1]=0. p[3]|*(p+3) by Rule #3 p[3]=3. result refers to the pointed object that is exactly a[3] The same as p[2] (a+2) is a pointer that points to a[2] The same as *(p-1). a with 3 is Rule #2. result refers to the pointed object that is exactly a[2] int* p = &a.

but only pointers to their first elements are passed (by value): void sort (int* p). this must be ensured by the program semantics. // because it can be called by: int a[10]. qsort(a). // a is converted into int* consequently. the arguments do not carry the information about the size of the array (C/C++ arrays do not carry this information).Arrays  arrays cannot be passed to functions by value (as entire packages of elements). // A fn that accepts an int* void qsort (int a[]). // Also accepts an int*. for example: int sumUp (int a[]. T[] and T* as types of arguments are treated uniformly  when arrays are passed as arguments. Copyright (C) 2003 by Dragan Mili ev 52/209 June 2003 . int numOfElements).

initialized to the given  values. p is a pointer (not an array) to char* p = ³World´. // Expects a null-terminated string // Returns the size of the string. all librarian functions that deal with strings expect such arrays. but it is not null-terminated! for that purpose. if an array is not terminated so. the function will not work correctly (it may loop until it accidentally comes across a null byte in memory): int strlen (char* p).¶l¶.¶o¶}. q is an array of // without counting in µ\0¶ 5 chars.¶e¶. there is a traditional C convention for the arrays of characters: they should be always terminated by \0 ( null-terminated strings ).¶l¶.Arrays H e l  l o w o r l d \0 for the same purpose (implicit information about array size). the compiler terminatesarray of 6 characters by s is an string-literals with \0 default: char s[] = ³Hello´. an array of 6 char q[5] = {¶H¶. chars Copyright (C) 2003 by Dragan Mili ev 53/209 June 2003 .

Chapter 6: Declarations and Scopes Declarations Scopes Global Scope Local Scope Class Scope June 2003 Copyright (C) 2003 by Dragan Mili ev 54 .

an object. // a function that // accepts a char* and an int and returns an int* class Counter. etc. // an object of type int int* p = &a. a reference.int). // a function that // accepts an int and returns no result int* g(char*. a function. // an object of type int* void f(int).Declarations A declaration introduces a name (identifier) into a program: int a = 3. // an object of type Counter* Any name in the program must be declared before it is used A declaration lets the compiler know about the language category of the name (a type.) and its type June 2003 Copyright (C) 2003 by Dragan Mili ev 55/209 . // a class named Counter Counter* pc.

Declarations After processing a declaration. generates the code for its initialization. or generates the code for a function body checks the usage of the name afterwards according to its category and type information from the symbol table. along with the information about the name s language category and type possibly allocates the space for an object. the compiler:     adds the name into its symbol table. and reports violations (compilation errors) knows how to compile the code when the name is used afterwards (declaration of an object) initializes (creates) an object or (declaration of a function) defines the body of a function or (declaration of a class) declares the members of a class A definition is a declaration that:    June 2003 Copyright (C) 2003 by Dragan Mili ev 56/209 .

// p and q are of type Counter*. they will have an undefined value (whatever is encountered in memory) June 2003 Copyright (C) 2003 by Dragan Mili ev 57/209 . // p has an undefined initial value Objects of built-in types do not have default initial value. unless they are explicitly initialized with an initializer. b.Declarations Declarations of objects:  which are not definitions (do not initialize objects): extern int a. b=0. extern Counter* theCounter. After such a declaration. // a has an undefined initial value Counter *p. *q = new Counter. an object can be used freely (all operations are allowed). provided it is defined somewhere in the program  which are definitions (do initialize objects): int a.

sqr(int). // sqr accepts an int. } int sqr(int i) { return i*i.Declarations Declarations of functions:  which are not definitions (do not define bodies): int f(). The name of formal arguments are not relevant in these declarations (the compiler ignores them). They should be provided in order to increase the readability. } June 2003 Copyright (C) 2003 by Dragan Mili ev 58/209 .  which are definitions (do provide bodies): void Counter::inc() { counter=counter+1. both return an int void Counter::inc(). provided it is defined somewhere in the program. // f has no arguments. the function can be used freely (it can be invoked). // a member of Counter After such a declaration.

objects can be defined and manipulated after such definitions Copyright (C) 2003 by Dragan Mili ev 59/209 June 2003 . of a constructor private: Counter* myCounter. but no other operations on these objects are possible. After such a declaration.  which are definitions (declare all members). class Clock { public: Clock(Counter*). // Decl. only pointers and references to objects of that class can be defined. }. used to reduce compilation dependencies among program modules: class Counter.Declarations Declarations of classes:  which are not definitions (do not declare members): class Counter.

Outside its scope.Scopes Scope is a part of the program source code in which a declared name can be used (it is said to be in scope) Scope is a notion exclusively bound to:   the space dimension (relates with a part of the program source code) compilation time (scopes are resolved at compilation time only and have no effects at runtime) A name can be used in its scope directly. the name can be accessed in a specific way or not used at all June 2003 Copyright (C) 2003 by Dragan Mili ev 60/209 .

the compiler searches the first enclosing scope. outward. the compiler reports an error ( name not declared ) The language defines the rules of scope nesting June 2003 Copyright (C) 2003 by Dragan Mili ev 61/209 . until a declaration is found if no declaration is found. etc. meaning the following:     when a name is used.Scopes Scopes can be nested: if a name is declared in a nested scope. the compiler tries to bind it to the declaration that describes that name it first tries to find the declaration in the inner-most nested scope (the current scope) if the declaration is not found there. it hides the same name declared in an enclosing scope.

} class Dummy { public: int x.Scopes Example: int x = 0. }. x = 3. void f () { int x = 1. the local x is no more in scope Start of a nested scope Hides the global x End of the nested scope. the member x is no more in scope Scopes in C++:     global (file) local (block) class function (not covered by this course) Copyright (C) 2003 by Dragan Mili ev 62/209 June 2003 . A global x of file scope Start of a nested scope Hides the global x Refers to the x from the nested scope End of the nested scope.

although it is hidden. in scope to the end of file void f () { // a nested scope int x = 2. over the :: operator: int x = 0. // access to the global x June 2003 Copyright (C) 2003 by Dragan Mili ev 63/209 . // access to x from the nested scope ::x = 3.Global Scope A name has the global scope if it is declared outside all classes and function bodies A global name is in scope from the place of its declaration to the end of the compilation unit (the source code file) A global name can be accessed from a nested scope. // access to the global x } // end of the nested scope int* p = &x. // hides the global x x = 3. // global x.

hides the global x void f () { Refers to the local x int x = 1. End of the nested scope } Refers to the first local x x = 3. hides the global int x = 0. including a function body A local name is in scope from the place of its declaration to the end of the block in which it is declared A block is a nested scope for an enclosing block or the file (the global scope): A global x of file scope A local x. Start of a nested compound statement x = 2. (block) and scope { A nested local x. .Local Scope A name has a local scope if it is declared inside a compound statement (a block between braces {}). andRefers to the second local x the enclosing local ones x = 2. June} 2003 Copyright (C) 2003 by Dragan Mili ev 64/209 int x.

} June 2003 Copyright (C) 2003 by Dragan Mili ev 65/209 .Local Scope The same declaration of a name can be repeated in the same scope. unless it is a definition Formal arguments of functions have a local scope of the outermost block of the function body: void f(int x) { // argument x has a local scope int x = 0. // Compilation error: // multiple definitions of the same name ...

. DBStatus getConnectionStatus(). structures. June 2003 Copyright (C) 2003 by Dragan Mili ev 66/209 .Class Scope A name has a class scope if it is declared inside a class definition. DatabaseManager (char* name).. failed. enumerations. // Constructor DBStatus openConnection(). private: char* name. all names declared inside a class definition are called its members:   data members and member functions types: typedefs. classes class DatabaseManager { public: enum DBStatus { ok. unions. DBStatus performQeury (char* sqlQuery). . }. DBStatus closeConnection(). refused }.

operator: void main (){ DatabaseManager* p = new DatabaseManager(. ..openConnection()... within the same scope: DatabaseManager::DatabaseManager(char* nm) { name = new char[.].. }  over a pointer of type X* and -> operator: p->openConnection().Class Scope A name with a scope of class X can be accessed:  directly... (*p). Copyright (C) 2003 by Dragan Mili ev 67/209 June 2003 .... }  over an object of type X and .). // name is in scope .. .

. Thus. because f is searched Start of a nested local scope for: void Derived::f the active local scope (not found) in () { . classes) . This is an error. scope is global class Derived : public Base { public: f() is from the scope of class Derived We want // redefined operation call the Base class class scope virtual void f(). toReactivation of that version of }.scope (and possibly the scopes of its base this is an endless recursion! Base::f(). in the active start the search from(found) class Correct: class scope Derived the Base f()..Class Scope  over the :: operator (X::memberName): class Base { public: virtual void f(). // polymorphic function End of scope of class Derived.. } June 2003 Copyright (C) 2003 by Dragan Mili ev 68/209 .. f(). the only active }.

If a class is defined inside another class. Status put (Object* anItem). error }..Class Scope Types can be defined in a class scope. }.g. no special access rights among the classes): class List { public: enum Status { ok. classes or enumerations. June 2003 Copyright (C) 2003 by Dragan Mili ev 69/209 ... // constructor //.. private: class ListElement { // nested class ListElement (ListElement*). e. }. .. this is only the matter of scopes and there is no other meaning (no object embodying. List ().

It } must be accessed this way. thus reducing chances for name clashing  they are logically packed into a proper class. because the List class scope return ok. is active ListElement is not in scope. except that:  they do not pollute the global name space.Class Scope Status is not in scope.} A nested type is used when it is needed only for an implementation of another class.. List::ListElement::ListElement (List::ListElement* next) {. allowing their encapsulation Copyright (C) 2003 by Dragan Mili ev June 2003 70/209 .. Nested types are generally equivalent to global types. It must be accessed through the operator :: List::Status List::put (Object* p) { . protected.. ok is now in scope.. or private). thus improving readability and understandability of the program  access to them may be controlled (they can be public.

Chapter 7: Object Lifetimes Object Lifetime Automatic Objects Static Objects Dynamic Objects Data Members Temporary Objects Object Initialization and Destruction June 2003 Copyright (C) 2003 by Dragan Mili ev 71 .

If it is an object of a class. The object can be accessed only during its lifetime In the beginning of its lifetime. its destructor is called. regardless of the lifetime category Lifetime is a concept orthogonal to scope:   it is time-related (instead of space-related) it is runtime-related (instead of compilation-related) June 2003 Copyright (C) 2003 by Dragan Mili ev 72/209 . its constructor is called. In the end of its lifetime. the object is destroyed. If it is an object of a class. There is no exception to this rule.Object Lifetime An object lifetime is the time interval from its creation till its destruction. an object is initialized.

Object Lifetime Categories of lifetimes in C++      automatic static dynamic data members temporary objects One of the main design principles of C++ is that objects of all types (built-in as well as user-defined) can be of all lifetime categories June 2003 Copyright (C) 2003 by Dragan Mili ev 73/209 .

..).. A new .. loop). int f (.. i<10. Automatic object.. a new incarnation of that A new is incarnation is created each created. i++) { initialized each time this block is Automatic object j is destroyed int j = i+5. until the execution exits its scope (block) Automatic objects are local objects not specified as static Every time the flow of control executes a definition of an Automatic object. f(. this allows nested and recursive function calls: time this function is called..... object automatic object.) { Recursion int i = .Automatic Objects An automatic object lives from the time of execution of its definition.. when the execution exits this block } } June 2003 Copyright (C) 2003 by Dragan Mili ev 74/209 . when the execution exits this block entered (each iteration of the Automatic object i is destroyed .. incarnation is created and for (i=0..

when it is finished. the semantics are the same as in the definition: X x1=x2.. } June 2003 and initialized by x2. When a function is called. the activation block is cleared from the stack. the formal argument is created as an automatic object and initialized by the actual argument.Automatic Objects Automatic objects are placed on the program control stack: when a function is called...} void g () { . Copyright (C) 2003 by Dragan Mili ev 75/209 .. the compiler compiles operations with automatic objects by addressing modes relative to the top of the stack Formal arguments of functions are automatic by their lifetime.f(x2). The initialization the time of function invocation for At semantics are the same as any other initialization: f(x2).. an activation block of its automatic objects is created on the stack.. local automatic x1 is created void f (X x1) {.

Automatic Objects
Objects of classes can be automatic, too. Constructors and destructors are invoked at the beginning and end of their lives:
void main () { Counter c1(3), c2(3); // automatic objects c1.inc(); // call inc() of c1 ... } // destructors of c1 and c2 are called here

Substitution does not take place for these objects, because they are always exactly the objects of the specified class known to the compiler, identified directly by their names:
Derived d; // an object of a derived class Base b = d; // b is certainly a Base, nothing else!

June 2003

Copyright (C) 2003 by Dragan Mili ev

76/209

Automatic Objects
An automatic object is created when the execution encounters its definition. Consequently, an automatic object does not need to be created at all; if it is not, it will not be destroyed, either (constructor and destructor will not be called):
void main () { ... if (...) { Counter c1(2); // c1 may never be created ... } // destructor for c1 is called here }

June 2003

Copyright (C) 2003 by Dragan Mili ev

77/209

Static Objects
A static object lives from the moment of execution of its definition, till the end of the program. There is only one incarnation of each static object during the execution of the program Static objects are: 


all global objects local objects declared as static
Counter c(2); // global static object void f () { static Counter c(3); // local static object }

June 2003

Copyright (C) 2003 by Dragan Mili ev

78/209

Static Objects
The moment of creation of a static object depends on its scope:  

global static objects are created at a moment on program startup, not necessarily before the invocation of main(); the moment of their initialization is not guaranteed; recommendation: avoid global static objects of classes local static objects are created when the flow of control comes to their definition for the first time; they are initialized only when the definition is encountered for the first time, every other time the definition is skipped;

Static objects are stored in a static memory space, allocated at compile time. Static objects of built-in types may often be initialized at compile time:
static int a = 5; // may be initialized // at compile time
June 2003 Copyright (C) 2003 by Dragan Mili ev 79/209

return &instance. the object will not be created nor destroyed (the constructors and destructors will not be called): Counter* Counter::Instance() { static Counter instance(0).Static Objects Local static objects are secure with initialization. } Here. the local static object is created (its constructor is called) when the function Instance() is first called. Recommendation: instead of global static objects of classes. If a definition of a local static object is never executed. use local static objects of classes. if ever June 2003 Copyright (C) 2003 by Dragan Mili ev 80/209 .

while b dies void main () { while (a<4) f(). // initialized only once cout<<" a = "<<a. void f () { int b=1. // initialized at each call static int c=1. cout<<" c = "<<c<<µ\n¶. a = a+1. } The output will be: a = 1 b = 1 c = 1 a = 2 b = 1 c = 2 3 Junea = 3 b = 1 c = Copyright (C) 2003 by Dragan Mili 2003 ev 81/209 . cout<<" b = "<<b. b = b+1. c = c+1. } // a and c survive return from f.Static Objects Local static objects survive over subsequent invocations of their enclosing functions: int a=1.

.Dynamic Objects The lifetime of a dynamic object is explicitly controlled by the program semantics. . and is explicitly destroyed by the operator delete: Counter* p = new Counter(3). } June 2003 Copyright (C) 2003 by Dragan Mili ev 82/209 . Dynamic objects survive the execution of functions and are not tied to implicit destruction. delete pc. void f() { pc = new Counter(2). A dynamic object is explicitly created by the operator new.. } void main () { f(). as automatic and static objects: Counter* pc = 0. delete p.

called the freestore or the heap. this behavior can be changed for a class initializes the object by  simple copying the result of the initializer expression init to the allocated space. by default.Dynamic Objects The operator new: new T(init)   allocates a space in memory to store an object of type T. however. the space is allocated in a special memory section assigned to a program. managed by a built-in memory manager. if T is a built-in type  calling the constructor of T that accepts the initializer init to initialize the object. if T is a class  returns the pointer to the created object of type T* Copyright (C) 2003 by Dragan Mili ev 83/209 June 2003 .

by default. ptr must point to an object created with new. // but the object is lost! The operator delete: delete ptr  if the result of the expression ptr is a pointer to a class. If that pointer is lost. otherwise a runtime error may occur June 2003 Copyright (C) 2003 by Dragan Mili ev 84/209 . calls the destructor for the object pointed to by ptr  releases the space allocated for the object. it is done by a built-in heap manager.Dynamic Objects The created dynamic object is always anonymous. // correct int p2 = new int(3). The sole link to it is the pointer returned by new.// no compilation error. // compilation error: // incompatible types int p3 = *new int(3). there is no way to access the anonymous dynamic object. but it can be changed for a class. even to delete it: int* p1 = new int(3).

which is then called for each element in order of indices. When an array is allocated:   all but the first dimensions must be evaluated at compile time. June 2003 Copyright (C) 2003 by Dragan Mili ev 85/209 . delete [] a. it must have a constructor that may be called without arguments. otherwise. the first dimension may be computed at runtime (this is the reason for creating dynamic arrays) no initializers can be specified:  if the type of the elements is a built-in type. a compilation error occurs  new returns a pointer to its first element A dynamic array must be deleted this way: delete [] str. the elements have undefined initial values. the values must be set in a separate loop  if the type of the elements is a class.Dynamic Objects Allocation of a dynamic array: char* str2 = new char[strlen(s1)+1]. T* a = new T[n][5].

or the program simply does not work as intended  Typical cases of occurrences:  A function creates a dynamic object. but not destroyed (forgotten deletes) Effect:  after a long run. but it is forgotten to be destroyed in the client s context: X* getAnX(). the freestore is exhausted  new then returns 0. // It is not obvious who is responsible // to destroy the returned object X* pX = getAnX(). // there is no ³delete pX´ afterwards June 2003 Copyright (C) 2003 by Dragan Mili ev 86/209 . possibly causing the null pointer dereferencing problem.Dynamic Objects A potential problem with dynamic objects: Memory Leakage   Cause: dynamic objects are repetitively created.

// client not responsible to delete X* createX(). delete pX2.Dynamic Objects  Cure:  Use a naming convention for functions that return objects for which the client code is responsible to delete: X* getAnX(). X* pX2 = createX().  Some tools that monitor execution of a system may help you to find memory leakage June 2003 Copyright (C) 2003 by Dragan Mili ev 87/209 . // client responsible to delete X* pX1 = getAnX()... .

// Constructor ~Clock().Data Members The lifetime of a data member object is bound to the lifetime of the enclosing object: it is created when the enclosing object is being constructed  it is destroyed when the enclosing object is being destroyed class Clock { public: Clock(). // Destructor private: The constructor of the data Counter c.  Clock::Clock() : c(0) { . // Data member object of isclass here member c called Counter }... } Clock::~Clock() { . } June 2003 The destructor of the data member c is called here 88/209 Copyright (C) 2003 by Dragan Mili ev ...

Data Members A data member is initialized in the list of initializers of a class constructor. behind :. This is the initialization of the data member counter Counter::Counter (int i) : counter(i) { counter = . This is not an initialization... but } an operation: counter has been already initialized June 2003 Copyright (C) 2003 by Dragan Mili ev 89/209 . }. private: int counter. Every other operation on the data member in the body of the constructor is an operation on an already initialized member: class Counter () { public: Counter (int i).

the initial value is undefined objects of classes are initialized by calling the constructor that may Error: counter data member cannot not be called without actual arguments. because the class a compilation error Clock::Clock() { Counter does not have a default . except that:    June 2003 . constructor! } a class always has a destructor built-in types do not have destruction destructors of data members are called after the completion of the body of the enclosed object s destructor Copyright (C) 2003 by Dragan Mili ev 90/209 Similar holds for destructors. there is initialized implicitly. before the body of the constructor is executed.. the initialization is implicit:   for objects of built-in types. if such a constructor doesbe exist in the class.Data Members Each data member is initialized in the list of initializers.. either explicitly or implicitly. If an explicit intializer for a data member does not exist in the list.

including results of function is a temporary. Temporary objects are result of (i+j) is aas results of The those created temporary. anonymous int double double f(double). including a function call  a temporary object is destroyed when it is not needed any more (as an operand of another operation). They are always anonymous:The result of (?-k) is a temporary. anonymous int anonymous int operations. The result of f(u) is a temporary.Temporary Objects The lifetime of a temporary object is short and under the control of the compiler: a temporary object is created as a result of an operation. int n = i + j ± k.  June 2003 Copyright (C) 2003 by Dragan Mili ev 91/209 . double int m = aCounter.val() is a temporary. sooner or later (the matter of the compiler) The result of call aCounter. anonymous double d = f(u)+log(x). log(double). anonymous The result of log(x) calls.val()+5.

created in the context of function invocation (in the context of an expression where the function call is). } .. anonymous X.. The temporary The result of f() is a temporary. as in: X temp(x1) are the same as for any other initialization: X f () { return x1. initialized object is initialized with the result of the expression in the at the moment semantics of this initialization return statement.. anonymous object. constructors and destructors are called consistently A result of a function call is a temporary. // an expression with a function call June 2003 Copyright (C) 2003 by Dragan Mili ev 92/209 .f(). at the moment when the function returns a value.Temporary Objects Regardless to the exact moment of their creation and destruction. temporary objects are initialized and destructed as all other objects: for objects of classes.. Theof function return.

provided that the object is either of a built-in primitive type. Except for a subtle difference.Object Initialization and Destruction In declarations. this is equal to the notation X x1(x2) At all other places. an object can be initialized using the notation X x1 = x2. an object is initialized using the notation X x1(list_of_initializers)optional An implicit initialization (without explicit initializers) is possible for:   built-in types. the initial value is undefined objects of classes that have constructors that can be called with no actual arguments June 2003 Copyright (C) 2003 by Dragan Mili ev 93/209 . or of a class that has a constructor that can be called with one actual argument.

the initialization of elements is always implicit Objects are destroyed (destructors are called for objects of classes):   June 2003 only if they have been constructed always in exactly the reverse order of their creation Copyright (C) 2003 by Dragan Mili ev 94/209 . the order is defined by the order of evaluation of operations elements of an array are created in the increasing order of their indices. the order is defined by the order of execution of their definitions or new operators for data member objects. regardless to the list of their initializations in the class constructors for temporary objects. and dynamic objects. the order of creation is defined by their order of declarations in the class. the order is undefined except for the objects in the same file for local static.Objects Initialization and Destruction The order of objects creation is defined in almost all cases:      for global static objects. automatic.

Chapter 8: Program Structure Structure of Units Compilation Linking Preprocessor June 2003 Copyright (C) 2003 by Dragan Mili ev 95 .

c and . a program consists of a number of units (modules). whereby a unit is one file with source code (usual extensions are . a name can be used only if it is previously declared.cpp) One file is a separate compilation unit: the compiler does not cross the boundaries of a singe file. a file must have the declarations for all names used in it A source file consists of declarations only (some of them being definitions):    global objects classes and other types functions Copyright (C) 2003 by Dragan Mili ev 96/209 June 2003 .Structure of Units In C and C++. A file is the only scope of compilation According to the the general rule. Therefore.

a: 3 f: . . B. A.obj June 2003 Copyright (C) 2003 by Dragan Mili ev 97/209 .. B.. .......cpp void f() { .... int a..Compilation int a = 3. ....a..f().. . } og: 0 qf: .... which will cause usage void f().?f.. space allocation void g() { . } a is a a definition Thisand tfdefinition isn must be declared before extern int a..obj oa: 0 of: 1 ....... .. g: a: ? .cpp A. qa: .... ..?a..

.......... B. ..obj . B..exe) The linker makes it in two passes:   makes a global map of .) and to make an executable program (P..exe A. qa: .. P. .?f.obj. . etc..obj B.. a: 3 f: .?a.. g: ..obj files and a symbol table of exported symbols and their computed global addresses resolves the references to imported symbols using the computed addresses from the symbol table Copyright (C) 2003 by Dragan Mili ev 98/209 June 2003 .. .Linking A.obj files (A. og: 0 qf: ... C.obj.obj....obj The linker has a task to collect a set of .obj C.obj oa: 0 of: 1 .

but the library which defines the symbol is not included in the linker s list multiple definitions of a symbol. the linker reports the names of the . because your code might not use the symbol at all.obj files Some libraries are provided with the compiler environment (e. possible cause: the symbol is used in an included library.lib files) The linker treats libraries in the same way as other . except that they are prepared by compiling and linking a set of source files (. the linker reports only the name of the . possible cause: multiple definitions in several .cpp files Copyright (C) 2003 by Dragan Mili ev 99/209 June 2003 .obj files.g.obj file which imports the unresolved symbol. standard libraries) Possible linker errors:   a symbol not defined.Linking Libraries have the same form and meaning as ordinary ..obj files that define the symbol. often very confusing.

B. extern int a. which different from the types  or by the linker. } The compiler will generate The type of a has been  either by the compiler. = a+3.Preprocessor Consequence: for each program element N that is defined in a file A and should be used in many other files B. because it does not have any idea aboutthe code that deals with a (typeless) of the symbols.cpp double a = 3.. because it does not consider that operates with the code cross-file changed into double declarations (a file is an independent compilation unit) is totally an int. the linker deals solely with mapping of double This error cannot be detected symbols to their addresses June 2003 Copyright (C) 2003 by Dragan Mili ev 100/209 . declarations must exist in all these files B The extern declaration Problem: how to keep the declarations consistent in case forgotten to be updated of modifications? Example: A....cpp void g() { .

It is a part of the C/C++ compiler (in a broader sense) Thus. when the directive is continued in the next line June 2003 Copyright (C) 2003 by Dragan Mili ev 101/209 . and transforms it into the output text that is passed to the compiler. so it does not recognize program elements The preprocessor is controlled by the preprocessor directives that specify the transformations of the text Preprocessor directives start with # and last till the end of line. the compilation (in a broader sense) is performed in two phases (or pipes): preprocessing and compilation The preprocessor works exclusively with the source code as a text. The preprocessor does not consider any language-related issues. except when the line ends with \.Preprocessor The preprocessor is a program that transforms the source code of a file before its compilation.

The mostly used one is #include ³filename´ The #include directive results in the complete contents of the included file put in lieu of the directive. which stores the include files of the user s program June 2003 Copyright (C) 2003 by Dragan Mili ev 102/209 . which usually stores the include files with the declarations of librarian elements #include ³filename´ the preprocessor starts searching for the file from another place. other #include directives This directive has two forms: #include <filename> the preprocessor starts searching for the file from a predefined place. usually defined by the user.Preprocessor There are several preprocessor directives in C/C++. The included text is preprocessed again for eventual preprocessor directives. e.g.

i. } June 2003 Copyright (C) 2003 by Dragan Mili ev 103/209 A. #include is used #include ³A..cpp int a = 3. the interface of the .h´ B. It consists of declarations of the program elements that are defined in this .h extern int a. and are to be used in other files Note that a .cpp module. .cpp file.cpp file.cpp void g() { . encapsulation is supported at module level.Preprocessor This mechanism can be used to solve the described problem. but only those that are to be used in other files.....e. For a . = a+3.h file should not contain the declarations of all elements defined in the . Instead of an explicit declaration.cpp file. This way. a header file is created (. although rudimentary and indirectly (not through a first-class language concept) A.h).

h files. but the difference for the programmer is significant: the declarations are now localized in one physical place.h file is modified. making modifications easier and error-free As a result.Preprocessor The effect is that the compiler encounters the same code as before. when a . which assumes that the compiler compiles the directives in . too (at least in order to create its symbol table) The programming environment may help in reducing recompilation by the make procedure.cpp files that include it must be recompiled (including transitive inclusions). especially in large projects June 2003 Copyright (C) 2003 by Dragan Mili ev 104/209 . all . However.cpp files. which selectively and automatically recompiles only necessary . the programmers should try their best to reduce compilation dependences between files.

. Every occurrence of N in the text will be replaced with the text 10 #define max(a. be replaced The text. and optionally replaces each occurrence of that symbol with the defined text (a macro Simply introduces a new symbol _A_h into the replacement): Introduces a symbol table into the preprocessor snew symbol Nmax into the #define _A_h Introduces a new symbol preprocessor s symbol table.. The compiler will see: int void f (int a.?) in the text will be givencompiler will see: int a[10]. It defines a symbol within the preprocessor (in its symbol table.. which has nothing to do with the compiler s one). .Preprocessor Another directive is #define. Every occurrence #define N 10 preprocessor s symbol table. } June 2003 Copyright (C) 2003 by Dragan Mili ev 105/209 .. int c = max(x/3.b) (((a)>=(b))?(a):(b)) replaced with the of max(?. int b){ c = (((x/3)>=(y+1))?(x/3):(y+1)). but the parameters will properly (parameterized replacement) int a[N]..y+1).

h class Counter { public: Counter(int). } .. even when completely identical June 2003 Copyright (C) 2003 by Dragan Mili ev 106/209 .Preprocessor Header files often contain definitions of classes (which declare the members): Counter.cpp #include ³Counter. void inc(). }.. Caution: multiple definitions of a class are not allowed. Counter. The entire definition of the class Counter is needed for the definitions of its member functions. private: int counter.h´ Counter::Counter (int i) : counter(i) {} int Counter::val () { return counter. int val().

.cpp The directives #ifdef/#endif and #ifndef/#endif process the enclosed text conditionally: the enclosed text is passed to the output of preprocessing only if the specified symbol is (not) defined in the preprocessor s symbol table: #ifdef _A_h ..h D.cpp file. // the symbol _A_h is defined #endif Copyright (C) 2003 by Dragan Mili ev A.h June 2003 107/209 ..h file with a class definition is included B.h The compiler will encounter multiple class definitions and will report an error! X.Preprocessor Problem: what if a . // some code that is compiled only if .. either directly or indirectly? C.h several times in a .

Preprocessor These directives are used:  to solve the multiple-class-definition problem: enclose the code of each header file like this: #ifndef #define .. // Windows-dependent code #elif defined(Linux) . it will be transferred to the compiler only the first time it is included  to enclose platform-dependent code: #ifdef Windows . // // // #endif _A_h _A_h The code of the header file.... // Linux-dependent code #endif June 2003 Copyright (C) 2003 by Dragan Mili ev 108/209 ...

Part III: Procedural Elements Operators and Expressions Statements Functions June 2003 Copyright (C) 2003 by Dragan Mili ev 109 .

Chapter 9: Operators and Expressions Expressions Operators Lvalues Overview of Selected Operators Summary of Operators June 2003 Copyright (C) 2003 by Dragan Mili ev 110 .

Expressions An expression is an element of a program that consists of operands (types. making compound expressions: a+b*c i + p->val(). objects. literals. or functions) and operations.b<<k cout<<³Counter = ³<<p->val()<<³\n´ When analyzing expressions. and returns a result. the number of operands) the types of the operands: the built-in operators require operands of strictly defined types the lvalue property of operands (to be explained soon) Copyright (C) 2003 by Dragan Mili ev 111/209 June 2003 . the result may be used as an operand of another operation. The operations are specified using the built-in operators An operation takes some operands and produces a result. the compiler checks:    the syntax of the expression (incl.

// + groups from left to right a*b/c // (a*b)/c. // * groups from right to left a+b+c // evaluated as (a+b)+c. in cases a result of an operator is used as an operand of the same operator // evaluated as a+(b*c). * and / have the same priority. // but group from left to right June 2003 Copyright (C) 2003 by Dragan Mili ev 112/209 .Expressions There is a default order of computation defined by:   the priority of operators and their direction of grouping: left to right or right to left. // * has a higher priority than + It can be modified by parentheses as usual (subexpressions): a+b*c (a+b)*c cout<<p->inc() // evaluated as cout<<(p->inc()) // -> has a higher priority than << **p = 3 // evaluated as *(*p).

A major part of the computation in a typical C/C++ program is in operations within expressions A side effect occurs when a function/operation that returns a result also modifies the state of its environment (e.Operators C and C++ are very rich in operators. side effects are considered harmful. because functions. In the classic theory of programming.g. since they reduce program readability. have unexpected effects As opposed to this belief. For most of them. the values of global variables or actual arguments/operands). the side effect is their primary role! This is a result of the fact that C was dedicated to concise and effective expressions. many operators in C/C++ have side effects: they modify their operands. which became very popular June 2003 Copyright (C) 2003 by Dragan Mili ev 113/209 . the focus of which is to produce a result.

It has two forms.Operators Example: the operator ++ increments the operand and returns a value. // a gets value of i before increment b = --k. and return its old value Similar holds for decrementing (--) (Hence the name of C++ .an incremented C. skeptics: what is the value of C++? :) a = i++. // b gets value of k after decrement Assignment is also an operator: except from assigning the value to its left operand (side effect!). and return the new value operand++: increment the operand. prefix and postfix:   ++operand: increment the operand. it groups from right to left: a = b = c // evaluated as a=(b=c) x = y = f()+z // evaluated as x=(y=(f()+z)) June 2003 Copyright (C) 2003 by Dragan Mili ev 114/209 . it returns the assigned value as its result.

because p is incremented twice in the latter June 2003 Copyright (C) 2003 by Dragan Mili ev 115/209 . not equivalent to *p++ = *p++ + 3.Operators There are operators of compound assignment: a+=b means the same as a=a+b. except that the expression a is computed only once: a += x -= u *= w /= *p++ b y++ v+3 z-+= 3 // // // // evaluated as (*(p++))+=3.

and whether its result is or is not an lvalue In most cases. an lvalue is an element that refers to a sound object in memory (but not a temporary object). although names of functions are also lvalues June 2003 Copyright (C) 2003 by Dragan Mili ev 116/209 . the compiler checks the consistency of the lvalue property of operators operands Lvalue is a property of a program element.Lvalues Apart from checking the types of operands an other things when analyzing expressions. it is a Boolean property: an element is or is not an lvalue:   a name of an object or a function is an lvalue for each built-in operator. it is defined whether it requires an operand that is an lvalue.

Lvalues In most cases. -. the fact that an operator requires an lvalue means that the operator requires a sound object in memory. but not for its right operand. etc. All operators that have side effects on an operand require that the operand is an lvalue The fact that an operator produces an lvalue as its result means that its result refers to a sound object and that it can be used as an operand of another operator that requires an lvalue Examples:  operator = requires an lvalue as its left operand (to produce the side effect). operators +. do not result in lvalues: a = (b+c) // correct: a is an lvalue (a+b) = c // incorrect: a+b is not an lvalue Copyright (C) 2003 by Dragan Mili ev 117/209 June 2003 .

too.. but does not produce an lvalue. but produces an lvalue..// correct: *(p+3) is an lvalue operation a<<b results in a s binary representation shifted b bits left. has a side effect)? If it did modify it. which refers to the object pointed to by the pointer operand: &a // correct: a is an lvalue &a = . consequently.. how to know whether this operator modifies its left operand (i.e. it would require an lvalue as its left operand.. it does not have a side effect Copyright (C) 2003 by Dragan Mili ev 118/209 June 2003 . check it in the summary table of all operands (to be given later) and see: << does not require an lvalue. it refers to the same object to which the left operand (as an lvalue) refers to: (a = b) = c // correct: a=b is an lvalue operator & requires an lvalue.Lvalues    operator = produces an lvalue.. in contrast. // incorrect: &a is not an lvalue &(a+3) // incorrect: a+3 is not an lvalue *(p+3) // correct: * does not require an lvalue *(p+3)=. operator * (pointer dereferencing) does not require an lvalue.

. & does not require // a modifiable lvalue June 2003 Copyright (C) 2003 by Dragan Mili ev 119/209 .. array.Lvalues The term lvalue has its origin in something that may be the left operand of assignment. or a constant object. f = . // incorrect: a is not a modifiable lvalue void f().. a = b+3. //incorrect: f is not a modifiable lvalue &f // correct: f is an lvalue. Only modifiable lvalues can be left operands of assignments: int a[N]. although all lvalues cannot be that A modifiable lvalue is an lvalue that is not a function.

and of the postfix form is not an lvalue: ++i = 5. Their result is an lvalue only if the member is an lvalue Increment (++) and decrement (--) operators require numeric operands. i-. and -> require an object and a pointer to an object as their left operands. respectively.= 5. and a member name as their right operand. The result of the prefix form is. June 2003 // correct: ++i is an lvalue // incorrect: i± is not an lvalue Copyright (C) 2003 by Dragan Mili ev 120/209 .Overview of Selected Operators Function call is also an operator that results in a temporary object initialized with the return expression: expr(listOfArgs) There is an operation of constructing a temporary anonymous object by explicit constructor call: Counter(0) Member access operators .

which is treated as False.. the result is 0 if (!p) . but only its type is determined at compile time.Overview of Selected Operators Operator sizeof returns the size of the operand. The unit of measurement is sizeof(char)==1. which is treated as True. a pointer. not a byte! Two forms:   sizeof expr: sizeof (a+p->inc()) sizeof(type): sizeof(Counter) Logic negation operator ! requires a numeric.. the result is 1 if the operand is not equal to 0 (symbolic value for pointers does point to an object). // if p is not 0 Copyright (C) 2003 by Dragan Mili ev 121/209 June 2003 . or an object that may be converted to a numeric or a pointer as its operand:   if the operand is equal to 0 (symbolic value for pointers does not point to an object). The operand (as an expression) is not evaluated at runtime.

^ (exclusive or) require integral operands and operate bit-by-bit Logic operators && (and) and || (or) require numeric operators or pointers and return 0 (false) or 1 (true). and % (remainder) requires integral operands.Overview of Selected Operators Arithmetic operators * (multiplication) and / (division) require numeric operands. and >= result in 1 (true) or 0 (false) Bit-wise operators & (and). != (not equal to). <. they do not have side-effects Relational operators == (equal to). >. otherwise. they consider whether an operand is equal to 0 (False) or not June(True) 2003 Copyright (C) 2003 by Dragan Mili ev 122/209 . If both operands are integral. <=. | (or). the result is integral. the result is a floating-point: a%b // the remainder of division a/b Shift operators a<<b and a>>b require integral operands and result in the binary representation of a shifted b bits left/right.

then b..Overview of Selected Operators Operator ?: is the only ternary operator: a?b:c First. j=0. Note that only one of the operands is evaluated. June 2003 Copyright (C) 2003 by Dragan Mili ev 123/209 .c // evaluated as (a.. and returns the result of b as its result.) is a binary operator: a. If the value of a is equal to 0 (false). and you want to do several operations: for (int i=0. It groups from left to right: a.j++) . b is evaluated and returned as the result. It must be of integral type or a pointer.b). a is evaluated. i<M && j<N. c is evaluated and returned as the result. If its value is not equal to 0 (true). never both Sequence operator (. i++.b.b evaluates a first.c It is used when the syntax requires one expression.

the operand is an expression that does not need to have an lvalue result. an lvalue expression is required as the operand Copyright (C) 2003 by Dragan Mili ev 124/209 June 2003 . if an operand is lvalue. because the result of the operator cannot be used as an operand of the same operator  lvalue: whether the result is an lvalue:  Y: always  N: never  Y/N: depends on one of the operands  usage: the way of usage. if an operand is expr.Summary of Operators The following table presents all operators in C++. while the groups are ordered by priority (decreasing). The table gives:   the operator and its meaning the way of grouping:  L: from left to right  R: from right to left  N/A: not applicable. The operators are grouped into groups of the same priority.

-> ++ -++ -sizeof sizeof new delete ~ ! + & * Meaning scope resolution global name access indexing function call object construction member access indirect member access postfix increment postfix decrement prefix increment prefix decrement size of object size of type dynamic object creation dynamic object destruction bitwise complement logic negation unary minus unary plus address of pointer dereferencing Grouping L L L L L L L R R R R Lvalue Y/N Y/N Y Y/N N Y/N Y/N N N Y Y N N N N N N N N N Y Usage class_name :: member :: name expr[expr] expr(list_of_expr) type_name(list_of_expr) expr .expr + expr & lvalue * expr R R R R R R June 2003 Copyright (C) 2003 by Dragan Mili ev 125/209 .Summary of Operators Operator :: :: [] () () . name expr -> name lvalue ++ lvalue -++ lvalue -.lvalue sizeof expr sizeof(type) new type delete expr ~ expr ! expr .

expr expr << expr expr >> expr expr < expr expr <= expr expr > expr expr >= expr expr == expr expr != expr expr & expr expr ^ expr expr | expr expr && expr expr || expr expr ? expr : expr / June 2003 Copyright (C) 2003 by Dragan Mili ev 126/209 .Summary of Operators () .* expr expr ->* expr expr * expr expr / expr expr % expr expr + expr expr .* ->* * / % + << >> < <= > >= == != & ^ | && || ? : cast pointer to member dereferencing pointer to member dereferencing multiplication division remainder addition subtraction shift left shift right less than less than or equal to greater than greater than or equal to equal not equal bit ise And bit ise Exclusive Or bit ise Or logic And logic Or conditional operator / / / (type) expr expr .

simple assignment multiplication and assignment division and assignment remainder and assignment addition and assignment subtraction and assignment sift right and assignment sift left and assignment bitwise nd and assignment bitwise r and assignment bitwise Xor and assignment sequence R R R R R R R R R R R L Y Y Y Y Y Y Y Y Y Y Y Y/N lvalue = expr lvalue *= expr lvalue /= expr lvalue %= expr lvalue += expr lvalue -= expr lvalue >>= expr lvalue <<= expr lvalue &= expr lvalue |= expr lvalue ^= expr expr . expr June 2003 Copyright (C) 2003 by Dragan Mili ev 127/209 .Summary of Operators = *= /= %= += -= >>= <<= &= |= ^= .

Chapter 10: Statements Basic Statements Conditional Statements Loop Statements Other Statements June 2003 Copyright (C) 2003 by Dragan Mili ev 128 .

expression as a statement. int i=a. but do not produce results as expressions A declaration is a kind of a statement: a declaration may occur wherever a statement may occur (not only at the beginning of a block) An expression terminated with . expression as a statement. } June 2003 // // // // // // start of a block declaration as a statement.Basic Statements Statements encompass some computation. a=(c++)+d. and you need more: { int a. is a statement A compound statement (a block) is a sequence of statements enclosed in braces {}. d=3. sequentially. end of the block 129/209 Copyright (C) 2003 by Dragan Mili ev . The statements in a block are executed in order. declaration as a statement. A block may occur whenever one statement is expected. c=0. i++.

Conditional Statements
Conditional statement if:
if (expr) then-statement else else-statement  the else else-statement part is optional 
 

if you need more than one statement, use a block the expr must result in a numeric, Boolean, or pointer value if the value of expr is not equal to 0 (true), then-statement is executed and the if statement is completed; otherwise, elsestatement is executed, and the if statement is completed if (a++) b=a; // equivalent with if (a++ !=0)... if (c) a=c; // equivalent with if (c!=0)... else a=c+1;

June 2003

Copyright (C) 2003 by Dragan Mili ev

130/209

Conditional Statements
Conditional statement switch:
switch (expr) { case const1 : list-of-statements1 case const2 : list-of-statements2 ... case constn : list-of-statementsn default : list-of-statementsd }  the default part is optional  expr must evaluate to an integral value  the control passes directly to the case label that has the guard expri equal to the result of expr, or to the default part otherwise  the execution is continued through the rest of the branches; if you want only one branch to be executed, use the break statement to exit the switch: switch (status) { case ok: commit(); break; case failed: alert(); break; case refused: retry(); break; }
June 2003 Copyright (C) 2003 by Dragan Mili ev 131/209

Loop Statements
Loop statement for:
for (init-statement expr1 ; expr2) statement  the init-statement is an expression or a declaration; it always ends with a semicolon ;  if you need more than one statement in statement, use a block  the expr1 must result in a numeric, Boolean, or pointer value  this is a while loop with an exit on top
init-statement ==0 

expr1 !=0 statement expr2
June 2003 

init-statement, expr2, and statement may be omitted expr1 is optional; 1 (true) is assumed if it is omitted
132/209

Copyright (C) 2003 by Dragan Mili ev

Loop Statements
Example: a usual counter loop in which the index i goes from 0 to n-1:
for (int i = 0; i<n; i++) { ... i ... }

The init-statement may be a declaration. This declaration introduces a name with the scope of the for statement (and its body) only:
for (int i = 0; i<n; i++) { ...i... // i is in scope here } if (i<n) ... // Error: i is not in scope here

Note: older versions of C++ had a different rule: the name introduced in init-statement had a scope of the block that enclosed for; the given example is completely valid in some versions of C++ (e.g. Microsoft C++)
June 2003 Copyright (C) 2003 by Dragan Mili ev 133/209

is equivalent to statement while (expr) statement Example: void strcopy (char* p.) statement Loop statement do-while is a loop with the exit at the end: do statement while (expr).expr. // Try to analyze this! } June 2003 Copyright (C) 2003 by Dragan Mili ev 134/209 . char* q) { while (*p++ = *q++).Loop Statements Loop statement while is a special case of for: while (expr) statement is equivalent to for (.

. } June 2003 Copyright (C) 2003 by Dragan Mili ev 135/209 .. The break statement breaks the first enclosing loop or switch: while () { // Endless loop ..) continue...... with an optional result of the associated expression: return expr..Other Statements The return statement returns from a function.) break. if (..) { ... if (.. . .. } The continue statement skips the rest of a loop body and passes to the next loop iteration: for (.

....) goto exit.. for (. such as exits from deeply nested loops: for (....) { .. } } } exit: . for (.. Statements in functions may be labeled.) { ...Other Statements The goto statement jumps to the specified label. June 2003 Copyright (C) 2003 by Dragan Mili ev 136/209 . labels have a function scope (visible throughout the entire function body.. if (.) { .. except for some structured constructs.. but not outside) The goto statement should not be used in structured programming. ....

Chapter 11: Functions Declaration and Invocation Inlining Default Argument Values Function Overloading June 2003 Copyright (C) 2003 by Dragan Mili ev 137 .

e. Dynamic function nesting (of function calls) is allowed. or by reference (C++) A declaration of a function that is not a definition does not need to have names of arguments (desirable only for readability purposes): int strcompare (char*. void strcopy (char* to.. char* from).char*). June 2003 Copyright (C) 2003 by Dragan Mili ev 138/209 . have a class scope) or non-members (global functions) Functions are the only kind of subprograms in C/C++: procedures are special kinds of functions that return no result (void as the return type) There is no static function nesting (nesting of function definitions) as in Pascal. Arguments are passed by value (C/C++). but need not have arguments.Declaration and Invocation Functions can be members of classes (i. including recursion A function may. for example.

at the moment of function return. } A function is called by the () operator. The result of a function call is a temporary object. June 2003 Copyright (C) 2003 by Dragan Mili ev 139/209 . The semantics of this initialization are the same as any other initialization: a = ptrCounter->inc() + b. which is a block. created at the place of invocation.Declaration and Invocation A function definition contains the function body. and initialized with the result of the return expression. A function may return the result through the return statement: int Counter::inc () { return ++counter.

Declaration and Invocation The type of a function is determined by:   the number and types of formal arguments.3). g(int. A function may be called over a pointer to it.3). p = g. This concept is used to dynamically bind call the function pointed to by p. the same as (*p)(7. T* and T[] are considered the same as types of arguments the type of the result. that is function calls (the traditional call-back mechanism fthat is obsolete in OO programming): int f(int.int) an int of) returns an Pointers to functions may be defined. only a p function cannot return an accepts pointer to (the first element and an array int: int(*)(int. (*p)(5.int) converted into a pointer to the function = &f. a pointer to a function may be redirected to point to different to f p points functions of the same type. a is a pointer to a function thatarray. because a function may be the same as p int (*p)(int. At runtime.3).int). because the function call p(7.int). = &g. operator () may accept a function or a pointer to a function as its first operand June 2003 Copyright (C) 2003 by Dragan Mili ev 140/209 .

the formal arguments are created as local automatic objects. //. initialized with the This constructor specifies a user-defined conversion this initialization an X actual arguments.. the corresponding constructor is invoked: X temp(2) Copyright (C) 2003 by Dragan Mili ev 141/209 ...f(1). because are may be initialized with an int. } void main () { . } June 2003 At the time of this function call. return 2.. the formal argument x1 is created as a local automatic object.. initialized with the actual argument 1. The semantics of from int to X. the same as any other initialization: class X { public: X(int). the corresponding constructor is invoked: X x(1) At the time of executing this return..Declaration and Invocation When a function is called. a temporary anonymous object that represents the result of f(1) is created and initialized with the result of the return expression.. }.. X f (X x) { //.

but still everything works well! However. a program looks like a bunch of declarations and trivial procedures. polymorphism) As a result. possibly with adapted arguments perform a simple computation. there is a tread-off. or call just a few other functions This is a consequence of a good separation of concerns and much of implicit semantics embodied in declarative parts of the program (inheritance. fetching the return address from the stack) may be much bigger than the execution of a small body of the called function June 2003 Copyright (C) 2003 by Dragan Mili ev 142/209 . because the overhead of a function call and return (storing the return address on the stack. many functions have very short bodies (usually less than 5-10 simple lines of code):    only set or return values of data members pass the call to other functions.Inlining In a well decomposed program. passing the arguments over the stack.

only the automatically generated machine code is redundant Copyright (C) 2003 by Dragan Mili ev 143/209 . the compiler puts the very code of the called function s body at the place of its invocation This is somehow opposite to the historical step in invention of procedural programming: instead of repeating the same piece of code at many places. It is called inlining: instead of generating the code for a function call. the code is extracted into a procedure that is called from different places. because   June 2003 inlining is done by the compiler and completely hidden from the programmer the source code is localized. there is a big difference. Inlining is the opposite technique: instead of extracting the code.Inlining For this reason. which may cure this problem. it is repeated at all places of usage However. a compiler optimization technique was invented a long time ago.

because the programmer may request inlining for a function. there is a compiler option that orders the compiler to inline the functions as it decides In C++. Usually. completely transparent to the programmer. and everything else is the same as before) June 2003 Copyright (C) 2003 by Dragan Mili ev 144/209 . and the rest is the same as for any other function It is important to emphasize that inlining is only an optimization technique. Such a function is simply specified as inline. not incorporated into the language itself. The program does not change its semantics by any means due to inlining (arguments and other automatic objects are initialized and destructed as described.Inlining In many other languages. inlining is the matter of compiler optimizations. inlining is a language concept.

in order to generate the code. a very short code of the body) June 2003 Copyright (C) 2003 by Dragan Mili ev 145/209 . Therefore. it cannot be inlined. For example. the compiler does not have to fulfill a requirement for inlining. many compilers do not inline functions with loops or local static objects Anyway. simply call another function. if a function is recursive.Inlining Moreover. this is not important for the programmer. only in the described cases (get or set a value. inline functions are usually defined in header files Inline functions should be used sparingly. because the semantics of the program are intact The compiler needs the entire definition (the body) of an inline function at all places of its invocations.

} . char* from) { while(*to++ = *from++)... here instead of in the class definition int Counter::val () { return counter. The keyword inline may be placed }.Inlining A global function is declared as inlined simply: inline void strcopy(char* to. }.. } A member function that is defined within a class Member functions may be declared as inline in several equivalent ways: definition is implicitly inline class Counter { public: int val () { return counter. or class Counter { The definition of an inline member public: function must follow the class definition inline int val (). in the same header file .. } June 2003 Copyright (C) 2003 by Dragan Mili ev 146/209 .

. .log(x). // means log(x.. If a formal argument has a specified default value and the corresponding actual argument is not supplied at the place of invocation....0) June 2003 Copyright (C) 2003 by Dragan Mili ev 147/209 . double base=10..} . the actual argument takes the default value: Counter::Counter (int init = 0) {.10.... // the same as Counter c(0) void List::insertAt(int at=0) {.. Counter c..Default Argument Values C++ allows declarations of default argument values.} double log(double arg..0)..

double arg). } June 2003 Copyright (C) 2003 by Dragan Mili ev 148/209 .log(.....x).. can be implemented as two functions: void f(int). // Error .0. . void f() { f(0).. // Not possible Default argument values are just a notational convenience that improves the readability and conciseness of programs. The function: void f(int=0).Default Argument Values Only the adjacent arguments from the tail of the argument list can have default values: double log(double base=10.

double) June 2003 Copyright (C) 2003 by Dragan Mili ev 149/209 . which may reduce program readability In C++.Function Overloading Sometimes there is a need to implement a set of functions that perform semantically the same operation. // max(char*. .. but with different (types of) arguments.5). // max(double. char* s = max(³March´.6. In traditional languages.char*). these functions must have different names. provided that they have arguments of different types. the target function is resolved according to the matching of types of actual and formal arguments: double max(double.char*) double d = max(3. This is called function overloading At the place of invocation. a set of functions may have the same name. char* max(char*.´January´).double)..

Function Overloading When it encounters an overloaded function call. this is a compilation error there are several functions that match the call equally. the resolution is obvious. the compiler resolves the call by comparing the types of actual with formal arguments (the result type is not considered). this is the only positive outcome there is no function that matches the call (no conversions are possible). But what if there is not. this function is called then. and there is still a function that may be called by converting actual arguments? The compiler uses a precise formal algorithm for resolving overloaded function calls. this is a compilation error an ambiguous function call Copyright (C) 2003 by Dragan Mili ev 150/209 June 2003 . If there is a complete match. The outcome of the algorithm may be one of the following:    there is exactly one function that best matches the call.

but it somehow prefers:   exact matches of types over conversions standard (built-in) conversions over user-defined conversions June 2003 Copyright (C) 2003 by Dragan Mili ev 151/209 . an overloaded function call is unambiguously resolved by the compiler.Function Overloading Sometimes. but it is not obvious to the programmer which one is actually called (due to subtle implicit conversions). Such calls should be avoided by:   explicitly casting the actual arguments to improve the readability renaming the functions so that the call is obvious The algorithm is very complex and not suitable for common programming.

and Objects Access Rights Constructors and Destructors Operator Overloading June 2003 Copyright (C) 2003 by Dragan Mili ev 152 . Members.Part IV: Classes Classes.

Chapter 12: Classes. and Objects Class Declaration Objects The Pointer this Static Data Members Static Member Functions June 2003 Copyright (C) 2003 by Dragan Mili ev 153 . Members.

full definition of B in B..h´ A::A(B* aB) : myB(aB) {. only pointers (or references) to The but its members is not needed for the the class may be defined.hare A.hcannot be used of A..Class Declaration A class declaration that is not a definition is class X.cpp June 2003 Copyright (C) 2003 by Dragan Mili ev 154/209 . private: . Thus..h declared). after such a declaration. #include ³A. because only pointers toare Such declarations B in declared.cpp.h is class A { included in A. its full definition is needed. used to reduce compilation dependencies: class A.. (because they are notdefinition It is not necessary to include B..haccess the B.myB->aFunction()..h´ #include ³B. void doSomething(). }. } A. To members of B. .. B* myB..... public: . A(B*).} void A::do() { .. B.

They can be:    types: enumerations. unions. or classes data members: objects of built-in or user-defined types member functions Member functions. including constructors. can be overloaded. structures. The rules for function call resolution are the same as for global functions June 2003 Copyright (C) 2003 by Dragan Mili ev 155/209 .Class Declaration The names declared within a class definition are called class members. They have the scope of the class.

the following can be done by default.) or pointers (operator ->) objects can be passed as arguments of functions  The semantics of some of these actions can be redefined by the programmer Other actions are not defined implicitly.Objects When a class is defined. with default semantics:      objects and arrays of objects can be defined pointers and references to objects can be defined objects can be assigned to each other (operator =) addresses of objects can be taken (operator &). but should be defined explicitly if needed June 2003 Copyright (C) 2003 by Dragan Mili ev 156/209 . and objects can be accessed over pointers (operator *) members can be accessed over objects (operator .

// the same as this->counter counter += i. return temp. } Every direct access to a member of the same class is implicitly resolved as an indirect access over the pointer this: int Counter::inc (int i) { int temp = counter. // the same as this->counter return temp. } June 2003 Copyright (C) 2003 by Dragan Mili ev 157/209 . this->counter += i. a local nonmodifiable pointer this is implicitly defined.The Pointer this In every (non-static) member function. It points to the object for which the function is invoked: int Counter::inc (int i) { int temp = this->counter.

C++ implements objects and member functions in a simple and efficient way. and an object is implemented as a simple structure of data members only By these mechanisms. this is an implicit. When such a function is called. A call x. first argument of every (non-static) member function.f() is implemented as an ordinary call f(&x). hidden.The Pointer this Actually. C++ implements member functions as ordinary global functions with the implicit argument this. yet providing the OO notation and semantics. the pointer to the object is passed as that argument: p->inc(i) // p is passed as this c.inc(i) // &c is passed as this In fact. and an impression that the object s own function is invoked June 2003 Copyright (C) 2003 by Dragan Mili ev 158/209 .

to which this points. For example. June 2003 Copyright (C) 2003 by Dragan Mili ev 159/209 . }. Its constructor requires a Y (X* anX) : myContainer(anX) {. Every object of Y must have a class Y { When an link to its container objectyof X...The Pointer this The pointer this can be used for linking objects by pointers. This is the object private: of X that is currently being constructed.} pointer to the container.} private: Y y. }. while we want Ys to know about their containers (to have linksEvery object of X must have to them): class X { public: X () : y(this) {. X* myContainer.. let objects of the class X contain objects of the class Y. an object of Y contained.. X is created. The link should be initialized through the constructor of Y. its member is public: initialized first.

When a new Counter is int Counter::numOfCounters the 0. = number is incremented.cpp file private: . }.. Counter::Counter (int i) : counter(i) { numOfCounters++.. created.Static Data Members Static data members are shared among all objects of a class: there is only one instance of a static data member A static data member is declared within a class definition by the specifier static. . All objects of Counter share the same value of numOfCounters. static int numOfCounters. has a class scope.. and must be defined in a .cpp file: Declaration of a static data member class Counter { Counter (int init). Definition of a static data member in a .. } June 2003 Copyright (C) 2003 by Dragan Mili ev 160/209 .

which improves the readability of the program they do not pollute the global namespace. static data members are preferable because:    they are logically packed into the corresponding class. Note: be careful (avoid) static data members which are objects of classes their initialization can be unpredicted Instead of static data members. because they have the same lifetime. the same as global static objects. or protected) Copyright (C) 2003 by Dragan Mili ev 161/209 June 2003 . However. and live till the completion of the program. They are created at a moment on the program startup (not completely determined). private. thus reducing name clashing problems. global static objects can be used for the same purpose.Static Data Members Static data members have static lifetimes. they have a class scope they can be encapsulated (they can be public.

Static Data Members Static data members are used when an information is shared among all objects of the class. static ListOfCounters allCounters. private: int counter. } . June 2003 Copyright (C) 2003 by Dragan Mili ev 162/209 . // non-static data member static int numOfCounters. not to a particular object.. allCounters. or is relevant to the class.. } ~Counter () { // destructor numOfCounters--. allCounters.remove(this). For example. }.add(this). when you want to count or collect the objects of the class: class Counter { Counter (int init) : counter(i) { numOfCounters++.

int c = Counter::getNumOfCounters(). static int getNumOfCounters () { return numOfCounters. June 2003 Copyright (C) 2003 by Dragan Mili ev or -> is not computed at all) 163/209 . A static member function class Counter { and can access directly only static members Counter (int init). A static member function does not have the pointer this. which has no }. even before any object is created .. A static member function can be called without } any object.Static Member Functions Static member functions represent services of a class. not of a particular object. and Declaration of a static member function is defined as any other member function: does not have this.. particular meaning (the expression in front of . c = pCounter->getNumOfCounters(). and cannot access a non-static member of the class directly A static member function is declared within a class definition by the specifier static. has a class scope. It can be also called for an object.

or protected) Instead of static member functions. private. they have a class scope they can be encapsulated (they can be public. which are not accessible to global functions Copyright (C) 2003 by Dragan Mili ev 164/209 June 2003 . However. thus reducing name clashing problems. except for the class scope and access rights (they can be public. or protected) they are members of the class and have access to private and protected members of the same class. static member functions are preferable because:     they are logically packed into the corresponding class. global functions can be used for the same purpose. private.Static Member Functions Static member functions have all properties of global functions. which improves the readability of the program they do not pollute the global namespace.

. // Not allowed want to allow . // Not allowed a class. objects of this class can be created this way only protected: Counter (int init) : counter(i) {...} .. because it is asked for toIfcreate an object): the class cannot be inherited! the constructor is private. This function is a member of }. } Now. and has the access to the protected constructor June 2003 Counter* p = Counter::create(5). class Counter { public: Counter* create (int init) { return new Counter(init).. For example. not ofCounter* p = object. it is notin the usual create objects of this class of any lifetime category way: void f(Counter c1) { // implement Static member functions are used toNot allowed services of Counter c2. creation of only dynamic objects of a class } (this is a service of the class.When all Functions possible to Static Memberconstructors are protected.. Copyright (C) 2003 by Dragan Mili ev 165/209 . this class. when you a particular new Counter(0). not an object.

Chapter 13: Access Rights
Basic Rules Friends

June 2003

Copyright (C) 2003 by Dragan Mili ev

166

Basic Rules
C++ supports encapsulation at the class level, by declaring members (data, functions, and types) as: 
 

public: accessible from any place where the class definition is in scope protected: accessible only from the scope of the same class and derived classes private: accessible only from the scope of the same class

Scope resolution is done prior to the access rights control: first, the declaration is found for a member according to the scope resolution rules, and access rights to that member are checked then; if access is not allowed, the compiler does not look for an accessible member in another scope Access rights are defined at a class level, not at an object level: a member function can access private members of all objects of the same class, not only of the same object (over this)
June 2003 Copyright (C) 2003 by Dragan Mili ev 167/209

Basic Rules
The class definition may contain arbitrary many access specifiers in any order; the default access level is private:
class X { ... // private is default protected: ... private: ... public: ... private: ... };

The modern style, however, recommends to place the sections in the order public, protected, private, according to the size of the community interested in those parts (interface to the world, interface to the derived classes as special clients, implementation)
June 2003 Copyright (C) 2003 by Dragan Mili ev 168/209

Basic Rules
Style recommendations for class design: 

avoid public and protected data members, except for strong reasons; encapsulate access to data members in member functions, because: 
you can better control access to a data member by a function;  if you need to change the way it is accessed, you don not need to

modify the client code  you can override the access in derived classes  

publish only member functions that implement designed operations (services) of the class protected are usually: 
simple data member access functions (get/set); they are likely to be

needed in derived classes, if appropriate  helper functions that are used for the implementation of other member functions; they are a consequence of a proper algorithmic decomposition of other methods and localization of common parts; they are likely to be used in derived classes, if appropriate
June 2003 Copyright (C) 2003 by Dragan Mili ev 169/209

}. a class should be designed so that it has privileged clients. but it is declared anywhere within the definition of the class as any other function..... // g is a member of class Y . In C++. These are called friends A friend function of a class is not a member of that class. it is possible to declare that a function or another class is a privileged client of a class. friend void f(int).Friends Sometimes. meaning that it may access the class private members. // f is a global function friend char* Y::g(). specified with friend: class X { . June 2003 Copyright (C) 2003 by Dragan Mili ev 170/209 .

Friends A whole class can be declared as a friend of another class. nor is it inherited June 2003 Copyright (C) 2003 by Dragan Mili ev 171/209 .. Friendship is not a symmetric or transitive relation. X(.). protected: friend class Creator. then all the members of the latter can be accessed from the scope of the former Example: you want only the class Creator to be allowed to create objects of a class X: class X { ... }..

it would be necessary to publish the members needed for privileged clients. example: an operation that multiplies a vector and a matrix notation: max(a. On the contrary. in x. thus breaking the encapsulation Copyright (C) 2003 by Dragan Mili ev 172/209 June 2003 .Friends The reasons for defining a global friend function instead of a (possibly static) member function:    the function operates with two or more classes. friends are declared in the very server class if friends did not exist. all clients would be able to access these members in that case.f(). and it is not converted otherwise The concept of friends does not break encapsulation. x must be an object that has a member f. it makes it stronger because:   encapsulation cannot be broken by intruders. however.max(b) allowed conversions: f(x) allows a conversion of x it it does not match the type of the formal argument. without the knowledge of a class and its designers.b) is more appropriate than a.

Chapter 14: Constructors and Destructors Constructors Destructors June 2003 Copyright (C) 2003 by Dragan Mili ev 173 .

constructors may be overloaded. the invoked constructor is determined according to the general overloaded function call resolution rules The access to a constructor may be controlled as for any other member function A constructor has the pointer this June 2003 Copyright (C) 2003 by Dragan Mili ev 174/209 .Constructors A member function that has the same name as its class is a constructor A constructor is called whenever an object of the class is created. At a place of object creation. A constructor may have arguments as any other function Therefore. regardless to its lifetime category A constructor does not have the return type.

if such does not exist.Constructors A constructor that can be called with no actual arguments (it either has no actual arguments. which:    is public and has no arguments performs the default initialization of the base class subobject by invoking its default constructor. the compiler generates an implicit default constructor. the initial value is undetermined  for objects of classes. if such do not exist. or all its actual arguments have default values) is called the default constructor If a class has no explicitly defined constructors. the default initialization is performed by invoking the default constructors. a compilation error is reported performs the default initialization of the data members:  for objects of built-in classes. a compilation error is reported June 2003 Copyright (C) 2003 by Dragan Mili ev 175/209 .

Constructors
Example:
class Counter { public: Counter(int); ... }; class Clock { private: Counter c; }; class Clock { public: Clock() {} private: Counter c; };
June 2003

Unless it is explicitly defined, there is no default constructor, because the compiler does not generate an implicit one, since there is an explicit constructor This class has no explicit constructors, so the compiler generates an implicit default one: public Clock::Clock () : c() {} Since Counter has no explicit data member a Although there is no default constructors, compilation error is is an implicit one : c() initialization, there reported Since Counter does not have a default constructor, an error is reported again

Copyright (C) 2003 by Dragan Mili ev

176/209

Constructors
When an object of a class is being created:
the adequate constructor is invoked  before execution of its body, the adequate constructor of the base class is invoked  the data members are initialized in order of their declaration in the class definition  the body of the constructor is executed class Clock { public: Clock (char* name,int initial); private: 3 2 1 Counter c; char* name; static int numOfClocks; }; 

Clock::Clock(char* n, int i) : name(n),c(i) { numOfClocks++; June} 2003 Copyright (C) 2003 by Dragan Mili ev

177/209

Destructors
A member function that has the same name as its class, prefixed with ~, is a destructor
class X { ... ~X (); // Destructor };

A destructor is called whenever an object of the class is destroyed, regardless to its lifetime category A destructor does not have the return type. A destructor may not have arguments. Therefore, a class may have at most one destructor The access to a destructor may be controlled as for any other member function A destructor has the pointer this
June 2003 Copyright (C) 2003 by Dragan Mili ev 178/209

Destructors
If a class has not an explicitly defined destructor, the compiler generates an implicit default destructor, which: 


is public performs the default destruction of the data members: 
for objects of built-in classes, nothing is done  for objects of classes, the destructors are called 

performs the default destruction of the base class subobject by invoking its destructor

Consequently, a class always has exactly one destructor, either explicitly defined or implicitly generated When an object of a class is being destroyed: 
 

June 2003 

its destructor is invoked the destructor s body is first executed after execution of its body, the data members are destroyed in the reverse order of their declaration in the class definition the destructor of the base class is invoked
Copyright (C) 2003 by Dragan Mili ev

179/209

} June 2003 Copyright (C) 2003 by Dragan Mili ev 180/209 . deallocate memory. delete associated dynamic objects. ~String () { delete str. } . close files. For example: class String { public: String () : str(0) {} String (char*). String char[] str String::String(char* s) { if (str = new char[strlen(s)+1]) strcopy(str. private: char* str... etc.Destructors Destructors are often used when there is a need to release some resources when an object is destroyed.g. }. e.s).

Chapter 14: Operator Overloading The Concept of Operator Overloading June 2003 Copyright (C) 2003 by Dragan Mili ev 181 .

which is not built in the language we must design a class to implement it We may define the operations on complex numbers as: class Complex { public: Complex(double re=0.. . imag.. double im=0. Complex c1(3.0)...The Concept of Operator Overloading Let us assume that we need an abstract data type of complex numbers.c2(1.c3. friend Complex add(Complex. .Complex).Complex). private: double real.-12.0. friend Complex sub(Complex.4.0).. }.3). c3 = add(c1. June 2003 Copyright (C) 2003 by Dragan Mili ev 182/209 ..c2).

real+c2. // the same as operator+(c1... }. double im=0. C++ allows definitions of operator functions.c2(1. } Complex c1(3. which have special names: class Complex { public: Complex(double re=0..Complex).. friend Complex operator+(Complex.The Concept of Operator Overloading However.0.3).-12. .c1.0). June 2003 Copyright (C) 2003 by Dragan Mili ev 183/209 . friend Complex operator-(Complex..4.imag+c2.c2) .. Complex c2) { return Complex(c1.0). c3 = c1 + c2. imag.imag).real. private: double real.Complex).c3. Complex operator+(Complex c1.

The Concept of Operator Overloading Operator functions are just like other functions. For many of them some special rules exist The details of this concept are beyond the scope of this course June 2003 Copyright (C) 2003 by Dragan Mili ev 184/209 . except that:   they have special names operator@. where @ is a built-in operator apart from usual explicit calls by their names. just like built-in operators This allows defining mathematical notations for abstract data types. they can be called implicitly in expressions. as well as special effects by overriding some operators for classes Almost all operators can be overloaded.

Part V: Derived Classes and Polymorphism Derived Classes Polymorphism June 2003 Copyright (C) 2003 by Dragan Mili ev 185 .

Chapter 15: Derived Classes Definition of Derived Classes Access Rights Constructors and Destructors June 2003 Copyright (C) 2003 by Dragan Mili ev 186 .

int add(int step). // Derived class: class ExtendedCounter : public Counter { public: ExtendedCounter(int init). }.Definition of Derived Classes The definition of a derived class needs a definition of the base class: class Counter { public: Counter(int init). June 2003 Copyright (C) 2003 by Dragan Mili ev 187/209 . }. private: int counter. void inc(). int val().

// inherited Counter::val() int i = p->add(3). and their own members defined in the derived class: ExtendedCounter* p = new ExtendedCounter(7). p->inc(). // ExtendedCounter::add() Every object of the derived class has an embedded subobject of the base class: Counter ExtendedCounter June 2003 Copyright (C) 2003 by Dragan Mili ev 188/209 . // inherited Counter::inc() cout<<p->val().Definition of Derived Classes Objects of a derived class have all members of the base class (although not all are accessible).

only public and protected members can be accessed (unless the derived class is a friend of the base class.Access Rights The keyword public in the header of the derived class definition means that the public members of the base class remain public in the derived class (interface inheritance). There is no way to break the encapsulation of the base class by force From the scope of the derived class. protected members of the base class remain protected for further derivation Private members of the base class remain private and inaccessible to the derived class. which must be explicitly declared in the base class) June 2003 Copyright (C) 2003 by Dragan Mili ev 189/209 .

The invocation will do the following:  invoke the corresponding constructor of the base class (and so on transitively). the invocation can be:  explicit. in the list of initializers of the derived class constructor.Constructors and Destructors When an object of a derived class is being created. there is an error ExtendedCounter::ExtendedCounter(int i) {}   the initialization of data members in order of their declaration (as described before) the execution of the derived class constructor body Copyright (C) 2003 by Dragan Mili ev 190/209 June 2003 . when the base class constructor is resolved according to the general resolution rules: ExtendedCounter::ExtendedCounter(int i) : Counter(i) {}  implicit. when the compiler generates an implicit call to the base class default constructor. its constructor is invoked. if such does not exist.

.the programmer should not call the base class destructor explicitly ExtendedCounter::~ExtendedCounter { . The invocation will do the following:    the execution of the derived class destructor body the destruction of data members in the reverse order (as described before) the invocation of the destructor of the base class (and so on transitively). its destructor is invoked. } Base class destructor is called here implicitly June 2003 Copyright (C) 2003 by Dragan Mili ev 191/209 .Constructors and Destructors When an object of a derived class is being destroyed. this invocation is always implicit ..

Chapter 16: Polymorphism Virtual Functions Virtual Destructor Substitution Arrays and Derived Classes Abstract Functions and Classes June 2003 Copyright (C) 2003 by Dragan Mili ev 192 .

Virtual Functions Polymorphism is supported through virtual functions: class Graphic class Picture { { * Picture Graphic public: public: virtual void draw (). 193/209 .. void addGraphic(Graphic*). Circle Rectangle Polyline class Circle : public Graphic { . class Rectangle : public Graphic { public: void Picture::draw () { virtual void draw (int i=0. }. } }... June 2003 Copyright (C) 2003 by Dragan Mili ev . i<numOfGraphics. }. . Graphic* . void draw (). draw() . myGraphics[i]->draw(). void removeGraphic(Graphic*). public: private: draw() draw() draw() virtual void draw ().. myGraphics[N]. int numOfGraphics. }.... i++) for ()....

and does not override it If a derived class does not override a virtual function. types of arguments. this is recommended to improve the readability The redefined function must match the entire signature of the virtual function (name. it is a new function that hides the inherited function. it inherits the implementation from the base class June 2003 Copyright (C) 2003 by Dragan Mili ev 194/209 .Virtual Functions The keyword virtual does not need to be put in a derived class. return type). Otherwise. however. because a virtual function remains virtual in all derived classes.

its proper destructor should be invoked. // p is a Base*. This is a key point in flexibility of OO software A client of an object may disregard its concrete type from the very moment of its creation. How to know which destructor (of the derived or base class)? delete p. From then on. there is a tendency to generalize things and to approach objects without knowledge about their specialties: the less you know the more freedom you have. When an object (of unknown type) is to be deleted. and ~Derived() should be called June 2003 Copyright (C) 2003 by Dragan Mili ev 195/209 .Virtual Destructor In OOP. the client may approach the object as a generalized thing: Base* p = new Derived.

void release (Base* p) { delete p. can be virtual.. as any other member function. release(new Base). // polymorphism } . // also virtual! }.. .. class Derived : public Base { public: ~Derived (). This allows the polymorphism of destruction: class Base { public: virtual ~Base(). // ~Base() will be called release(new Derived)..Virtual Destructor A destructor. }. // ~Derived() will be called Copyright (C) 2003 by Dragan Mili ev June 2003 196/209 .

the object s type must be specified at least on its creation) When a class has a virtual function and an explicit destructor. and thus it may be virtual A constructor is a function that transforms a piece of raw memory into an object of a class. the destructor of the base class should not be called explicitly it is always called implicitly A destructor is a function that transforms a live object into a piece of raw memory.Virtual Destructor The virtual destructor remains virtual in all derived classes In the destructor of a derived class. consider declaring the destructor as virtual. It is invoked for a live object as any other operation. because you count on polymorphism. It cannot be virtual (after all. which may result in deleting objects over pointers to the base class June 2003 Copyright (C) 2003 by Dragan Mili ev 197/209 .

over such an intermediary. which may be implicit. only the base class interface is accessible: p->aDerivedFunction(). supports the fundamental OO substitution rule: whenever and wherever an object of a base class is expected. an object of any derived class may occur This holds for accessing objects over intermediaries (pointers and references): a pointer to a base class may point to any (direct or indirect) instance of that class: Base* p = new Derived.Substitution The standard (built-in) C++ conversion Derived*pBase*. Of course. // Error! This is a consequence of the fact that an object of a derived class is a kind of an object of the base class June 2003 Copyright (C) 2003 by Dragan Mili ev 198/209 .

but it cannot be performed implicitly. // Now OK. pD->aDerivedFunction(). Derived* pD = (Derived*)pB. but can be unsafe This is an interpretation of the fact that an object of the base class does not necessarily need to be an object of a derived class June 2003 Copyright (C) 2003 by Dragan Mili ev 199/209 .Substitution The opposite conversion Base*pDerived* is also standard. . the programmer takes the responsibility for that action: Base* pB = new Derived.. The compiler cannot guarantee that an intermediary to a base class refers to a derived object..

Base b.Substitution Consequently. June 2003 Copyright (C) 2003 by Dragan Mili ev 200/209 . Base* pb=new Derived. } Base::f() is called class Base { public: virtual void f(). virtual void f(). public: delete pb. }. g(&d). polymorphism takes place: void main () { Derived d. g(pb). class Derived : public Base { g(&b). }. when an object is approached over an intermediary (a pointer). } Derived::f() is called void g(Base* pb) { Derived::f() is called pb->f().

there is no polymorphism.Substitution On the other side. class Derived : public Base { Base b. }. }. g(d). g(*pb). when an identifier represents an object. Base* pb=new Derived. } Base::f() is called b is nothing but a Base June 2003 Copyright (C) 2003 by Dragan Mili ev 201/209 class Base { public: virtual void f(). and no substitution is possible: void main () { Derived d. virtual void f(). public: g(b). } Base::f() is called void g(Base b) { Base::f() is called b. .f(). but not an intermediary (a pointer). delete pb.

objects in OOP should be always approached over intermediaries! In C++.Substitution When an object of a base class is initialized with an object of a derived class. or data members). unless you want to prevent substitution and polymorphism June 2003 Copyright (C) 2003 by Dragan Mili ev 202/209 . Base b = d. Conclusion: since substitution and polymorphism lie in the core of OO philosophy and represent its fundamental contribution. automatic objects. use pointers (or references) to objects instead of objects by values (as arguments of functions. it is initialized with the latter s inherited part only (the extension is cut off): Derived d.

it can be called with an array of derived objects (D[]... D*) June 2003 Copyright (C) 2003 by Dragan Mili ev 203/209 . i. when a function expects an array of base objects (B[].e. C++ does not prevent from making such a conceptual error: Derived[] p Derived* (C conversion for the sake of efficiency) Derived* p Base* (C++ conversion to support substitution) As a result. However. because a truck cannot be parked in it.e. B*). although cars and trucks are kinds of vehicles Due to two completely unrelated standard conversion that can be done implicitly in a chain.Arrays and Derived Classes An object of a derived class is a kind of an object of a base class. a collection/set/array of objects of the derived class is not a kind of a collection/set/array of objects of the base class Example: a parking for cars is not a parking for all (kinds of) vehicles. i.

then to Base* (C++ standard conversion) The result is undefined.bi=77. void f(Base* b) { cout<<b[2]. The size of Base is one int class Derived : public Base { Calculated as *(b+2). b+2 is calculated by adding public: int di. It is implicitly converted to Derived* (C standard conversion).Arrays and Derived Classes class Base { public: int bi. d[2]. } d is a Derived[]. The size of Derived is two size of Base to b two times the ints }. }.bi. because b points to an array of Derived. Since b is a Base*. which are larger than Base June 2003 Copyright (C) 2003 by Dragan Mili ev 204/209 . f(d). } void main () { Derived d[5].

b[0]=&d1. int i) { cout<<b[i]->bi. b[2]=&d2..b2.bi=77. } . Derived d1. Derived d. because elements are f(b. // No substitution. Base* b[5].. b[0] is exactly a Base As a conclusion. pointers June 2003 Copyright (C) 2003 by Dragan Mili ev 205/209 . do not define arrays of objects stored by Conversion Derived*pBase* values.d3. if you count on substitution and polymorphism.d2. . but arrays of pointers instead: void f(Base** b. Conversion Base*[]pBase** Base b1..Arrays and Derived Classes Apart from this problem. Correctly calculated. b[0]=d.2). d2. when arrays of objects by values are used.. there is no substitution: Base b[5]. b[1]=&b1.

. ... int i). Derived* d[5]..Arrays and Derived Classes In that case. f(d. the described conceptual error is not possible: Derived*[] p Derived**.. but it cannot be converted to Base** : void f(Base** b. .2). Error: Derived** cannot be converted to Base** June 2003 Copyright (C) 2003 by Dragan Mili ev 206/209 .

Abstract operations are used to generalize services of concrete specific classes.. }.Abstract Functions and Classes An abstract operation (an operation that has no implementation) is implemented in C++ as a pure virtual function and declared with =0: class Graphic { public: virtual void draw () = 0. but when those services cannot have default implementations June 2003 Copyright (C) 2003 by Dragan Mili ev 207/209 . ..

the function remains abstract. because they cannot be invoked from derived classes) If a derived class does not provide an implementation for an abstract function.Abstract Functions and Classes When a class has an abstract operation. Such pointers always point to instances of concrete derived classes June 2003 Copyright (C) 2003 by Dragan Mili ev 208/209 . and the class is also abstract Pointers to abstract classes can be defined. The opposite is not true: a class may be abstract with all operations implemented In C++. it is also abstract (it has no direct instances). although direct instances of that class do not exist. a class can be made abstract by declaring its constructors as protected (not as private.

Part VI: Conclusions An Example from Your Domain? Summary What s Next? Questions and Answers Discussion Evaluation June 2003 Copyright (C) 2003 by Dragan Mili ev 209 .

Sign up to vote on this title
UsefulNot useful