Introduction to C++ - University of Central Florida

Download Report

Transcript Introduction to C++ - University of Central Florida

An Introduction to C++

COP 4331: OO Processes for Software Development © Dr. David A. Workman School of EE and Computer Science University of Central Florida January 19, 2007 September 3, 2008

The UNIX C++ Environment

Getting Started

Your C++ Working Directory C++ Source Files

Header-files .h

Source-files .cpp

g++ Compiler C++ Object Files (.o) .h files contain module interfaces .

cpp files contain module implementation details The program entry point is the main() function that must be defined in a .cpp

file.

September 3, 2008

> g++ -c filename.cpp

One or more compilation-only steps.

Each successful compilation produces a .o

file. Only .cpp

files are compiled.

.h

files will be compiled when a #include statement is processed.

> g++ -c filename.cpp >& filename.msg

This illustrates how to redirect

stderr

to a file to save compilation messages.

(Note: In C++ the standard files are: cin, cout, cerr) > g++ mainfile.o file1.o file2.o … -o executable-name

Compile the main file, link .o files, and produce an executable.

(c) Dr. David A. Workman 2

C++ Program Organization

Organization Principle: All C++ programs should consist of a (.cpp) file holding the main() function together with a collection of paired header (.h) and implementation (.cpp) files that represent one or more of the following: (a) a Class type (b) an single Object defined by a namespace (c) a namespace encapsulating a collection of Classes and other related C++ entities AppProgram.cpp

Main() ClassA.h

ObjectX.h

Header File Header File IOMgmt.h

Header File ClassA.cpp

ObjectX.cpp

….

IOMgmt.cpp

Implementation File Implementation File Implementation File

September 3, 2008 (c) Dr. David A. Workman 3

C++ Organization (contd)

Alpha.h

Example.cpp

#include "Alpha.h" #include "Beta.h" #include "IOMgmt.h" using namespace IOMgmt; int main() { InMgr finMgr( "Enter name of input file:"); ifstream& fin = finMgr.getStream(); Alpha One; //Class type One.Extract( fin ); //Class operation Beta::Initialize(); //Operation on single object Beta ….

finMgr.close(); return 0; } #ifndef _ALPHA #define _ALPHA //includes go here class Alpha { public: Alpha(); void Extract( ifstream& fin) throw(TokenError ); … private: // declare data members here }; #endif Alpha.cpp

{ } #include "Alpha.h" Alpha::Alpha() //Constructor Class Module { void Alpha::Extract( ifstream& fin) throw(TokenError ) //procedure if( … ) throw TokenError( "Bad Syntax", "Alpha::Extract()"); } …

September 3, 2008 (c) Dr. David A. Workman 4

C++ Organization (contd)

Beta.h

Single Object Module (namespace) Example.cpp

#include "Alpha.h" #include "Beta.h" #include "IOMgmt.h" using namespace IOMgmt; int main() { InMgr finMgr( "Enter name of input file:"); ifstream& fin = finMgr.getStream(); Alpha One; //Class type One.Extract( fin ); //Class operation Beta::Initialize(); //Operation on single object Beta ….

finMgr.close(); return 0; } #ifndef _BETA #define _BETA //includes go here namespace Beta { void Initialize() ; // other function and procedure declarations … } #endif Beta.cpp

#include “Beta.h“ using namespace Beta; // other includes needed by the implementation of Beta namespace Beta { // define private data – visible to rest of namespace Beta void Initialize { //body of procedure Initialize (initializes private data above) } For other examples of Single Object namespaces, see IOMgmt::FileParser & IOMgmt::Concordance } … bodies of other functions and procedures of Beta

5 September 3, 2008 (c) Dr. David A. Workman

C++ Organization (contd)

Namespace Module (see IOMgmt) AppError IOMgmt TokenError OutMgr IOError InMgr Tokenizer StringTokenizer Not used in this course.

September 3, 2008 (c) Dr. David A. Workman 6

Unix Make Utility Program

makefile

make Your C++ Working Directory

September 3, 2008

C++ Source Files (.h, .cpp) C++ Object(.o) Files Executable File (a.out)

(c) Dr. David A. Workman 7

Make Files

See Notes

# makefile for foo_to_v5d.c conversion program (this is a comment) PROGRAM = lab_2 CFLAGS = -c CC = g++ LIBS = -lm OBJECTS =

$(PROGRAM).o file1.o file2.o … filek.o

# introduces comments

identifier =

declarations

$(PROGRAM): $(OBJECTS)

$(CC) $(OBJECTS) $(LIBS) -o

$(PROGRAM) $(PROGRAM).

o:

$(PROGRAM).

cpp $(CC) $(CFLAGS) $(PROGRAM).cpp >& $(PROGRAM).err

file1

.o:

file1

.cpp

file1.

h $(CC) $(CFLAGS) ...

file1

.cpp

filek

.o:

filek

.cpp

filek.

h $(CC) $(CFLAGS)

filek

.cpp

Identifier : introduces a rule

File0: File1 File2 … Filek command

To "run" a makefile : > make

or

> make -f

makefile-name

September 3, 2008 (c) Dr. David A. Workman 8

September 3, 2008

Makefile Example

apperror.cpp

iomgmt.cpp

simmgmt.cpp

simmodels.cpp

includes apperror.h

Includes includes includes iomgmt.h

Includes simmgmt.h

Includes includes simmodels.h

Includes simapp.cpp

Compilation Dependency Graph

(c) Dr. David A. Workman 9

executable

Makefile Example

Link in Math library Name of the executable simapp: simapp.o simmodels.o simmgmt.o iomgmt.o apperror.o

g++ -l m -o simapp simapp.o simmodels.o simmgmt.o iomgmt.o apperror.o

apperrors.o: apperror.cpp apperror.h

g++ -c apperror.cpp

Names of object files needed to create executable iomgmt.o: iomgmt.cpp iomgmt.h apperror.h

g++ -c iomgmt.cpp

simmgmt.o: simmgmt.cpp simmgmt.h iomgmt.h apperror.h

g++ -c simmgmt.cpp

simmodels.o: simmodels.cpp simmodels.h simmgmt.h iomgmt.h apperror.h

g++ -c simmodels.cpp

simapp.o: simapp.cpp simmodels.h simmgmt.h iomgmt.h apperror.h

g++ -c simapp.cpp

September 3, 2008 (c) Dr. David A. Workman 10

C++ Example

See Notes info1.cpp

#include #include #include

// format manipulator operations with parms // string class using namespace std

;

// using directive for standard C++ namespace void

Get_Text( string& Data );

// global function declaration int main() {

// This program prompts the user for: name, phone, and address.

// variable and object declarations:

const char

Blank = ' ';

string

Blank_Line(25,Blank); // initial string of 25 blank chars

string

Name; // initialized to the null string

string

Phone; // initialized to the null string

string

Address[3]; // array of 3 string objects // Executable statements

… see next slide return 0;

// OK, no errors

} void Get_Text( string& Data ) { // function definition // string& is the "pass by reference" operator cin >> Data; // Extraction for string expects a sequence of non-wsp chars }

September 3, 2008 (c) Dr. David A. Workman 11

C++ Example (continued)

// Prompt for user's name.

cout

<< "Enter your name: "; // Insertion operator << Get_Text( Name); // cin >> Name;

// Prompt for user's phone.

cout

<< "Enter your phone # (aaa)xxx-xxxx: "; Get_Text(Phone); // cin >> Phone;

// Prompt for user's address.

cout

<< "Enter each of three address lines.") <<

endl

;

cout

<< "Press ENTER for blank lines." <<

endl

;

for( int // Always end your programs with a EOL to clear the system output buffer // before returning to the OS.

cout

i = 0; i < 3; i++) Get_Text(Address[i]); << '\n'; // cout << endl; // cin >> Address[i]; September 3, 2008 (c) Dr. David A. Workman 12

• • • • • •

Summary of Features

CLASSES

Classes are defined in C++ using two encapsulation features: class and struct . Classes and Structs define a new type. Classes and Structs differ in the visibility rules to "member" data and function declarations . Class and Struct declarations should be placed in header files (.h).

Member function and data definitions are placed in a corresponding source file (.cpp).

FILE IO

C++ supports stream IO on external files. You must #include to use these features.

EXCEPTIONS

Exceptions are special classes used for error handling at runtime. An exception is an instance of some class created by a throw statement. A “throw” interrupts the normal flow of control and transmits the exception instance up the call chain until a catch block is encountered that will handle the exception type. (Exceptions in C++ are very similar to Exceptions in Java)

NAME SPACES

Name spaces are like package declarations in Ada and in Java. They create a named frame for encapsulating related types, data, functions, classes, and even nested namespaces. Names declared in a name space are accessed using the scope resolution operator (::), unless a using declarative is given.

SCOPE and VISIBILITY RULES TEMPLATES

Template classes in C++ are similar to generic packages in Ada. C++ also supports template functions , which are similar to generic subprograms in Ada.

September 3, 2008 (c) Dr. David A. Workman 13

Types, Values and Objects in C++

Primitive C++ types

– –

char, int, float, double, void // C types bool, wchar_t // new primitive types (Boolean, wide character) bool is an integer type with two predefined values (false = 0, true = 1) wchar_t is a 16-bit character type used to represent the international char. set

Composite C++ types

– –

struct, union, enum // C structured types - different properties in C++ class // C++ encapsulated type Example. In C struct t { int x; float y;}; // type is (struct t) struct t A; A.x = 5; // variable of type (struct t) // component reference

C++ unions and enums are similar to structs and classes

Example. In C++ struct t { int x; float y;}; t A; // “struct” no longer required A.x = 5;

September 3, 2008 (c) Dr. David A. Workman 14

Pointers and References Definitions

A pointer is a value that denotes a program location. A pointer variable is a variable that holds pointer values. The type associated with a pointer variable or value constrains the kind of object or variable at the designated location.

A reference is a name designating a program location.

Examples

int x, y; int *p = &x; // p is a pointer variable that can hold the location of integer variables int &q = y; // q is a reference constant that can hold the name of integer variables.

// q and y are now names of the same variable.

// references must always be initialized and cannot change thereafter!!!

int *f() { return &x; } // result is a pointer value designating the location of x int &g(){ return x; } // result is a reference value denoting an alias for x.

void swap( int *a, int *b){ int t = *a; *a = *b; *b = t; } //call: swap(&x, &y); void swap( int &a, int &b){ int t = a; a = b; b = t; } //call: swap(x, y); // swap( x, y ) is the same as swap( x, q) using the last defintion of swap().

g() = y+2; // Valid?? If so, what does it do?

September 3, 2008 (c) Dr. David A. Workman 15

#include #include using namespace std; const int cutoff = 6000; const float rate1 = 0.3; const float rate2 = 0.6;

File IO

int main() { // file object declarations ifstream fin; // ifstream is a subclass of fstream for input streams fin.open("income.dat“, ios::in); // external file name specified in open method ofstream fout; // ofstream is a subclass of fstream for output streams fout.open("tax.out“: ios::out); int income; float tax; // declarations are compiled and have their effect as encountered while ( fin >> income ){ // equates to "true" until EOF is encountered (fin != 0) if( income < ::cutoff ) // :: cutoff refers to the global name “cutoff” tax = ::rate1*income; // implicit type conversion between int and float else tax = ::rate2*income; fout << "Income = " << income << " Drachma \n" << " Tax: " << (int) tax*100.0 << " Lepta" << endl; See Notes } }//while fin.close(); // close file objects fout.close(); return 0;

September 3, 2008 (c) Dr. David A. Workman 16

#include

File IO

#include using namespace std; int main() { // file object declarations double rate1 = 0.23, rate2 = 0.37, cutoff = 50000.00; string fin_name, fout_name ; cout << “Enter name of input file: “; cin >> fin_name ; cout << endl; cout << “Enter name of output file: “; cin >> fout_name ; cout << endl; ifstream fin; fin.open( fin_name.c_str() ); // convert from string to char [] (C style) ofstream fout; fout.open( fout_name.c_str() ); int income; float tax; while ( fin >> income ){ if( income < cutoff ) tax = rate1*income; else tax = rate2*income; fout << "Income = " << income << " Drachma \n" }//while << " Tax: " << (int) tax*100.0 << " Lepta" << endl; fin.close(); // close file objects fout.close(); return 0; }

September 3, 2008 (c) Dr. David A. Workman

See Notes

17

Classes Definition class

typename

{ [

private data and function members // default visibility access-specifier : data and function members

]+

See Notes Page

} [

– –

object-list

] ;

A class introduces a new encapsulated type, members

• • • •

private public = visible only to the

class methods

protected = visible anywhere the class is visible .

Default access

typename . Access-specifier determines visibility of declared data and function

and

friend functions

= visible to methods of any subclass (derived class) is private , or the value of the most recent access-specifier.

Data members: act like C struct components; object attributes and state variables. The encapsulated data associated with each class instance is the collection of all declared data members, regardless of their individual visibility properties. A distinct copy of all (non-static) data members are allocated and initialized each and every time a class constructor is called.

Member methods : define operations on class instances. They hide the details of implementation of class instances and manage instance data.

September 3, 2008 (c) Dr. David A. Workman 18

Classes Semantic Rules

1. Class constructors perform two function in this order:

a) Allocate each (non-static) data member in the order declared.

b) Initialize each data member in the order declared. Primitive types are initialized implicitly to their default value, or explicitly from constructor parameters. Composite data members are initialized implicitly by calling the default constructor for the appropriate class or struct, or explicitly by calling a parameterized constructor. Arrays are treated as composite types and the array elements are initialized in a manner determined by the element type – as described above.

c) The constructor body is executed.

2. Explicit Initialization (Constructors)

a) Constructor( [

parameters

] ):

data-member

(

expression

), … { … } : Initialization List between colon and { b) Required to initialize (non-static) const class type.

data members or data members of some

3. Class destructors perform two functions in the following order:

a) The body of the destructor is executed.

b) The class destructor (if defined) is called for each (non-static) composite data member in the reverse order of their declarations.

c) The storage allocated to all (non-static) data members is de-allocated in the runtime stack.

September 3, 2008 (c) Dr. David A. Workman 19

Class Definition Example

“Person.h” See Notes Page #include using namespace std; class Person { string name ; // private data member (instance of class string) int age ; // private data member float salary ; // private data member public: Person ( string s, int a ); // public parametric constructor (creates instances) virtual ~ Person (); // public destructor (reclaims instance memory) string NameIs () const { return name; } // public inspector (read-only), in-line int AgeIs() const { return age; } // public inspector , (read-only), in-line float SalaryIs() const {return salary; } // public inspector , (read-only), in-line void GetOlder (); // public effector(mutator) void GetRaise ( float amount ); // public effector(mutator) }; NOTES:

(1) (2)

(3) (4)

A class declaration

should be defined in a header file.

A constructor

and

destructor

methods have the same name as the class and MUST NOT have declared type; destructors should be declared

virtual

to force redefinition in subclasses.

A

const

method cannot change data members unless they have been declared mutable .

If the body of the method is given in the class declaration (interface), the method is to be

expanded in-line

by the compiler wherever it is referenced AND must not also be defined in the implementation file (.cpp file)!

September 3, 2008 (c) Dr. David A. Workman 20

Class Implementation Example

“Person.cpp” Constructor requires two parameters.

#include //redundant – included by Person.h below.

Default constructor NOT defined.

using namespace std; #include "Person.h" Person::Person( string s, int a ) {

// public constructor (creates instances)

name = s; age = a; Destructor is the “default”. It simply } salary = 0.0; Person::~Person() } { See Notes

// public destructor (reclaims instance memory)

deallocates instance memory AFTER calling the destructors for any data members that are instances of other classes (e.g. name ) void Person::GetOlder() {

// public mutator

age += 1; } void Person::GetRaise( float amount ) salary += amount; {

// public mutator

} Mutators change instance attributes.

References to data members are components of the instance to which the method is called.

September 3, 2008 (c) Dr. David A. Workman 21

Class Client

#include #include using namespace std; #include “Person.h” int main() { Person me(“Alfred E. Newman”, 5), you(“John Doe”, 0); me.GetOlder(); you.GetRaise( 500.0 ); cout << “My name is “ << me.NameIs() << endl; cout << “My age is “ << me.AgeIs() << ‘\n’; cout << “Your salary is “ << you.SalaryIs() << ‘\n’; }

September 3, 2008 (c) Dr. David A. Workman 22

Class Design Principles

1. Only methods should be public .

2. Data members should always be private . Public inspector (read only) methods should be defined to return their value.

3. A default constructor and destructor should always be declared public; the destructor should be declared virtual to force subclasses to redefine them.

4. Destructor methods can default unless the class has data members that are pointers to dynamically allocated memory – this memory must be explicitly de-allocated in the destructor method for the class.

5. A class should have a parametric constructor that enables the definition of all data members.

6. A class should have a parametric constructor and/or an Extract() method that extracts an instance from an external data source (e.g. file stream), if dictated by requirements; a separate constructor and/or overloaded Extract() method should be provided for each different type of external input data source.

7. A class should have an Insert() method that outputs an instance to an external data sink (e.g. file stream); Insert() should be overloaded for each type of external data sink dictated by requirments. 8. The class should be designed to ensure that either an instance of the class cannot be constructed, or, alternatively, cannot be operated on by any other method unless all data members have consistent values that satisfy design constraints for the class. An exception should be thrown by any method that finds the instance state to be incompatible or in violation of class design constraints.

9. A class should be documented with comments , either in the class header file or the class implementation file, stating all design constraints on class data members.

10. A class should NOT define so called "setter" methods that allow clients to directly change the value of a data member. If this rule is violated, then such methods should at least validate design constraints and throw an exception if the constraints are violated by the new value of the data members.

11. "Constant" instances of a class should never be made public as immutable class instances. Instead they should be represented by parameterless functions that return the desired constant instance (value). e.g. Complex Zero(); //Returns the complex value (0.0, 0.0).

Complex ReUnit(); //Returns the complex value (1.0, 0.0) Double Pi(); //Returns the value of PI as a double precision floating point value.

Exceptions Basic Facts

Exceptions are objects , that is, instances of exception classes or primitive types. They are created dynamically and automatically by C++ when erroneous primitive operations are attempted (e.g. division by zero), and they can be created by a program throw block when erroneous conditions arise that the program can detect.

Exception objects contain data that explain or may be helpful in diagnosing the cause of the erroneous condition. Usually this data is a message identifying the point where the exception occurred and, if possible, why it may have occurred.

An exception handler is an action taken by the program invoked in response to an anticipated exception. Exception handlers are defined by catch blocks and are only executed when an exception of the appropriate type is raised within its scope of influence.

Exception handlers are bound to code segments that may throw exceptions they can accept via a try block .

– –

Unhandled exceptions propagate up the dynamic call chain and result in abnormal program termination.

C++ automatically performs certain “clean up” operations when exceptions go unhandled as they propagate up the dynamic call chain.

September 3, 2008 (c) Dr. David A. Workman 24

1.

2.

3.

Exceptions: Design Principles

Exceptions should never be caught (handled) in the same method or function that throws them – they should be handled by some active method or function earlier in the call chain at the time the exception is detected.

Exceptions should be caught at every opportunity in the call chain. The "exception message" and "exception origin" information should be updated (appropriately) to allow traceability and to give users and developers the most information possible about the cause of the exception and the conditions exiting at the time the exception occurs.

An exception should be propagated up the call chain to some method (or methods) having the most information to decide how the exception should be handled (recovery or termination).

September 3, 2008 (c) Dr. David A. Workman 25

Example: Exceptions

Stack.h

#include “AppError.h” class Stack{ // stack of integers int topidx; int *contents; public: Stack(); // constructor ~Stack(); // destructor needed void push( int x) throw(AppError) ; int pop() throw(AppError) ; bool empty(); // throws stack overflow and // stack underflow exceptions Header file name should NOT be different from class name.

} Stack.cpp

#include “Stack.h” Stack::Stack(){ // constructor contents = new int[10]; topidx = -1; } Stack::~Stack(){ // destructor needed delete [] contents; } Exception of type AppError void Stack::push( int x) throw(AppError) { if ( topidx >= 9 ) throw AppError("Stack Overflow") ; contents[++topidx] = x; } Throw clauses must agree in header and implementation files Each class is always responsible for checking for erroneous conditions and throwing exceptions when they occur.

} int Stack::pop() throw(AppError) { if (topidx < 0 ) throw (char *) “ Stack Underflow” ; return contents[topidx--]; Exception of type (char *) bool Stack::empty(){ return topidx < 0; }

September 3, 2008 (c) Dr. David A. Workman 26

Example: Exceptions

#include #include using namespace std; #include “Stack.h” #include "AppError.h" int main( ) { Stack s; int x; bool more; File 1 (Stack Client) Client code is always for(;;){ //An infinite for-loop cout << “Enter next value: “ << endl; try { cin >> int; // input exception possible s.push(x); // stack overflow exception possible cout << “Do you want to continue? ( 1=yes | 0=no )” << endl; cin >> more; // input exception possible }//try if ( !more ) break; catch (AppError msg){ cout << msg.getMsg() << endl; cout << “Stack Contents: “ << endl; while( !s.empty() ) cout << s.pop() << endl; return 1; } //catch Responsible for detecting And handling exceptions.

catch (…){ // handles any exception cout << “Unknown Exception!” << endl; return 1; } //The default handler should always //be placed last among handlers }//for return 0; }// main

September 3, 2008 (c) Dr. David A. Workman 27

Name Spaces

Definition

A namespace is an encapsulation unit used to group declarations and definitions with a common scope. Namespaces can encapsulate the following kinds of declarations:

Constant and variable declarations

– –

Struct, union, and class declarations Function prototypes

– –

Function definitions Nested namespaces.

There are three kinds of namespaces:

Global namespace : an anonymous namespace composed of all non-static external declarations that do not belong to any other named or unnamed namespace. Select visibility is enabled via the anonymous scope resolution operator (::identifier).

Translation unit namespaces : unnamed namespaces defined within a file; they limit the scope of external declarations to the given file; each file defines a unique TU namespace (if declared); TU namespaces obviate the need for global static declarations; declarations in TU namespaces and global declarations are indistinguishable within the same file – only global declarations can have visibility outside the file in which they are defined. Select visibility is enabled via the anonymous scope resolution operator (::).

Named namespaces: have an associated identifier that must be unique among all named namespaces. Select visibility is enabled via the scope resolution operator (namespace id::identifier).

September 3, 2008 (c) Dr. David A. Workman 28

Namespaces USES

1. To organize a group of modules for independent and parallel develop by different teams (or individuals). By limiting the scope of names to the namespace, naming conflicts can be avoided when independently developed namespaces are integrated after development.

2. To organize a group of related classes that have a common purpose in the design. For example, subsystems may be encapsulated by namespaces.

3. To implement one-of-a-kind objects (efficiently) without having to create the extra overhead associated with defining classes and restricting the number of instances that can be created.

September 3, 2008 (c) Dr. David A. Workman 29

Name Spaces

Global Namespace See Notes Translation Unit Namespace (one per file) Translation Unit Namespace (one per file) … Translation Unit Namespace (one per file) Named Namespace Named Namespace … Named Namespace

September 3, 2008 (c) Dr. David A. Workman 30

One file

Named namespaces

namespace alpha { int One; typedef int *INTPTR; INTPTR copyint( int value ) { One = value; INTPTR p = new int(One); return p; }//copyint

The namespace “alpha” is directly visible – it is declared in the global namespace.

}//alpha } int main() { alpha::INTPTR p; int x = 25; p = alpha::copyint(x);

Names defined within alpha must be referenced using the scope resolution operator (::), since they are not directly (globally) visible.

September 3, 2008 (c) Dr. David A. Workman 31

Named namespaces

Three files NOTE: The 3-file approach is preferred.

alpha.h

#ifndef ALPHA #define ALPHA namespace alpha { extern int One; //data declaration typedef int *INTPTR; INTPTR copyint( int value ); //fn decl.

}//alpha #endif #include "alpha.h" int main() { alpha::INTPTR p,q; int x = 25; p = alpha::copyint(x); } q = alpha::copyint(alpha::One);

September 3, 2008

#include “alpha.h” namespace alpha { int One; //data definition typedef int *INTPTR;

alpha.cpp

INTPTR copyint( int value ) { //fn defn One = value; INTPTR p = new int(One); return p; }//copyint }//alpha

(c) Dr. David A. Workman 32

Namespace Extension

File1.cpp

#include #include using namespace std; #include alpha.h

void f( float ); // global fn prototype; } int main() { alpha::INTPTR p; int x = 25; p = alpha::copyint(x); cout << “p = “ << *p << endl; cout << “alpha::One = “ << alpha::One << endl; f( float(x)); // type conversion

File2.cpp

#include #include using namespace std;

An extension to alpha File2.cpp

File2.cpp

{ namespace alpha typedef float *FLTPTR; float Two = 0.0; FLTPTR copyflt( float value ) { //fn defn Two = value; FLTPTR p = new float(Two); return p; }//copyflt }//alpha

See Notes Page

September 3, 2008

//code that uses the local extensions to alpha

(c) Dr. David A. Workman 33

Alpha.h

Namespace Extension

#ifndef ALPHA #define ALPHA { namespace alpha extern int One; //data declaration typedef int *INTPTR; INTPTR copyint( int value ); //fn decl.

Any other files that need to reference Information defined in namespace Alpha Only need to include “Alpha.h” to gain use of features contributed by both File1.cpp

and File2.cpp

extern float Two; //data declaration typedef int *FLTPTR; FLTPTR copyflt( float value ); //fn decl.

}//alpha #endif

September 3, 2008 (c) Dr. David A. Workman 34

See Notes Page

TU namespaces

File1.cpp

#include #include #include using namespace std; extern double pi; //defined in another file double h( double ), h2(double); namespace { // scope limited to this file double f( double x) { }//g } //f return x * sqrt(x) }//namespace double g(double x){ // global namespace return sqrt(x)/x;

File2.cpp

double g( double ); // refers to g in file 1 namespace { // visible to h() and h2() const double pi = 3.1415926; double f( double x) { }//f return x * g(x); }//TU namespace int main() { double y = 25.0* pi ; cout << “y^1.5 = “ << f(y) << endl; cout << “y^-0.5 = “ << g(y) << endl; }// main

September 3, 2008

double h2( double y){ return }//h2

(c) Dr. David A. Workman

pi *y*g(y);

This “pi” hides “::pi” and is only visible in File2.

{ double h( double y) return y/f(y); }//h

Refers to the local “pi” not “::pi”

35

Namespace declarations and directives

• •

Using Declarations

A using declaration adds a specific name declared in a namespace to the local frame where the using declaration is specified.

Using Directive

A using directive applies to namespaces as a whole, and simply makes all names declared in the namespace directly visible (without the scope resolution operator).

namespace beta { int X, Y,Z; } int Z; // global Z int main(){ int X = 0; // local X using namespace beta ; //directive X++; // local X Y++; // beta::Y Z++; // error (::Z or beta::Z )?

::Z++; // global Z beta::Z++; // beta Z ...

}

September 3, 2008

namespace beta { int X, Y,Z; } int Z; // global Z int main(){ int X = 0; // local X using beta::X ; //declaration ( error) using beta::Y ; //declaration ( localizes) } using beta::Z ; //declaration ( hides ::Z) X++; // local X Y++; // beta::Y Z++; // beta::Z ...

(c) Dr. David A. Workman 36

September 3, 2008

Namespace Aliases namespace

alias-name

=

namespace-id

;

namespace beta { int X, Y,Z; namespace delta { float X,Y,Z; } } int Z; // global Z namespace D = beta::delta; //alias declarations int main(){ int X = 0; // local X using namespace beta; //directive X++; // local X beta::X++; // X in beta Y++; // beta::Y using D::Z ; //declaration ( hides ::Z and beta::Z) Y++; // beta::Y Z++; // beta::delta::Z D::X++; // beta::delta::X }

(c) Dr. David A. Workman 37

Namespaces (More Rules) Data definitions in namespaces

If data definitions are intended to be made public ( bad practice !), they must be declared extern in the header file and then defined in the implementation file.

Data definitions of a primitive type can be defined with initializers in the implementation file.

Data definitions of a class or struct type whose memory must be allocated at runtime (e.g. dynamic arrays) must be defined as pointer variables and then dynamically allocated and initialized explicitly by a procedure call during execution (you should define a special procedure (or proceduress) that serves as an initializer for the namespace.

September 3, 2008 (c) Dr. David A. Workman 38

}

Namespaces as Single Objects

Object.h

#include “AppError.h” namespace

Object

{ // Declare C++ functions representing methods of the namespace object.

// At least one of these function must always be defined to properly initialize // the object’s environment before any other method can be called. These //

initialization functions

serve the same purpose as constructors of a class // type. The default initialization method is declared below.

void Initialize(); } Object.cpp

#include “Object.h” namespace

Object

{ void Initialize() { } Define encapsulated data members here. Primitive data can be directly initialized. Data members of a Class type may have to be defined as pointers and intialized by the initialization method(s). Special boolean protocol variables may have to be defined to ensure Initialize() method is called before any other methods.

Define the bodies of the functions declared in the header file. The bodies are defined using The same syntax you would use for functions in C, but they have direct visibility to all data members defined at the top of the namespace.

September 3, 2008 (c) Dr. David A. Workman 39

Concordance.h

#ifndef _CONCORD #define _CONCORD #include #include using namespace std; #include "Word.h" #include "Reference.h"

Namespaces as Single Objects

Concordance.cpp

#include using std::list; #include "Concordance.h" #include "Entry.h" namespace Concordance { void AddWordRef( Word& Wrd, Reference& Ref); void Output( ostream& fout); } #endif namespace Concordance { { list Contents ; void AddWordRef ( Word& Wrd, Reference& Ref) for (list::iterator I = Contents.begin(); I != Contents.end(); I++) { if ( Wrd < I->GetKey() ) {Contents.insert(I,Entry(Wrd,Ref)); return ;} if ( Wrd == I->GetKey() ) }//for {I->AddRef(Ref); return ; } Contents.push_back(Entry(Wrd,Ref)); }// AddWordRef #include "Word.h" #include "Reference.h" #include "Concordance.h" } Client Code int main() { Word aword; Reference aref; Concordance::AddWordRef(aword,aref); Concordance::Output( cout ); void Output ( ostream& fout) { for(list::iterator I = Contents.begin(); I != Contents.end(); I++) I->Output(fout); }// Output }// Concordance

September 3, 2008 (c) Dr. David A. Workman 40

Figure 2

#include “Object.h” int main() { ….

Object::Initialize(); // Call Object initialization fn … Object::Function1(…); // Call Object procedure … x = Object::Function2(…); // Call Object function }

September 3, 2008 (c) Dr. David A. Workman 41

Team1

Team Development with Namespaces

SystemX SubA Class One Class Two Main SubB TeamA TeamB

September 3, 2008 (c) Dr. David A. Workman 42

SubA

Team Development with Namespaces

Ted.h

TeamA: Ted Sally Fred Contains all and only the information Ted needs to make public (for other teams and/or other team members) Ted.cpp

#include “SubA.h” using namespace SubA; #include “SubB.h” namespace SubA { //Ted’s Code } SubA.h

Contains all public declarations for namespace SubA. This is used by clients of SubA (other teams) as well as members of Team A.

September 3, 2008 (c) Dr. David A. Workman 43

• •

Subclasses & Inheritance Syntax

class B { // base class definition // declaration of data and function members … }; class S : public B { // S is a public subclass of B (or derived class of B) // declaration of additional data and function members // redefinition of inherited member functions (optional) };

Semantic Rules

– – –

all members of base or super class are inherited by public members the subclass of the base class are public in the subclass private members of base class are NOT visible to subclass ( private data members can be indirectly accessed only via public functions provided in the base class )

members in the base class can be shared with (made visible to) its subclasses, by declaring them protected

access to inherited members can be made more restrictive (e.g. public to private) by explicitly re-declaring the member in the subclass with a private using declaration for the base class member.

September 3, 2008 (c) Dr. David A. Workman 44

Subclasses & Inheritance Semantic Rules (continued)

1. Constructors for derived classes initialize instances in the following way:

a) Allocate base class data members.

b) Initialize base class data members (implicitly using default base class constructor or explicitly using parameterized base class constructor defined in the initialization list.) c) Allocate derived class data members.

d) Initialize derived class data members explicitly from initialization list or implicitly by default value or default derived class constructor.

e) Execute the body of the derived class constructor.

2. Destructors for the base class and all derived classes should be defined as virtual to ensure that dynamic binding is used for derived classes.

3. Destructor bodies may need to explicitly de-allocate heap storage referenced by pointer data members. (e.g. dynamically created arrays )

September 3, 2008 (c) Dr. David A. Workman 45

Subtypes Definition: Type S is a subtype of T, if every legitimate value of S is also a legitimate value of T ( “is a” relation)

UCFstudent Attributes1 Methods1 IS-A Inheritance CSmajor Attributes1 Attributes2 Attributes and behaviors unique to CSmajors Methods1 Methods2 In UML the “IS-A” relation is meant to model the subtype relation between two classes.

An instance of CSmajor inherits the characteristics (attributes) and behavior (methods) of its superclass UCFstudent . But, in addition, a CSmajor has characteristics (attributes) of its own that make it different from other UCFstudents and may have certain behavior (methods) that are also unique to CSmajors.

All UCFstudents have a pegasus email address and account.

All CSmajors (after taking COP 4232) have written at least one discrete event simulation. Every CSmajor can do anything a UCFstudent can do (although they probably wouldn’t want to), but there are things a CSmajor can do that a UCFstudent cannot do (e.g., write good C++ code) Reference:

Object-Oriented Software Development Using Java, 2

ISBN = 0-201-73733-7

nd Ed

., by Xiaoping Jia, Addison-Wesley,

September 3, 2008 (c) Dr. David A. Workman 46

Overriding vs Overloading Methods Definition: Overriding

Refers to the definition of an instance method in a subclass that has the same name, signature, and return type as a method in the superclass when the type of the superclass is substituted for the type of the subclass.

EXAMPLE class Shape { private: public: stl::list vertices; Shape(); //default constructor Instance of Overloading (operations on the same subtype) Shape( ifstream& fin); (same name, different profiles) Shape( stl::list pts ); double perimeter(); //sums the distance between adjacent vertices string toString(); }; class Rectangle: public Shape { public: Rectangle( Point upperL, Point lowerR ) ; double perimeter(); // 2*(short side + long side) string toString(); }; Instances of Overriding (operations on different subtypes) (same name, same profiles)

September 3, 2008 (c) Dr. David A. Workman 47

Subtype Principles and Concepts Definition: Substitutability of subtypes.

An instance of a subtype cam appear wherever an instance of its supertype can appear or is expected. An instance of a subtype can always substitute for an instance of its supertype .

Definition: Conversion of class types is governed by the subtype relationship.

Conversion from a class subtype to one of its supertypes is called “ widening ” or “ upcasting ”. Conversion from a supertype to one of its subtypes is called “ narrowing ” or “ downcasting ”. Widening is always allowed and is carried out implicitly by the compiler.

Narrowing is allowed at compile-time, but may not be safe and may cause exception at run-time .

Conversion between class types is different from conversion between primitive types: primitive type conversion may result in changing the underlying representation of values (e.g. int to double ), but in class type conversion, the value of the object does not change – only the methods that are called to manipulate it change.

Reference:

Object-Oriented Software Development Using Java, 2 nd Ed

., by Xiaoping Jia, Addison-Wesley, ISBN = 0-201-73733-7

September 3, 2008 (c) Dr. David A. Workman 48

};

Example: Subclasses & Inheritance

class Food { public : Food() { cost = price = 0.0; } //in-line default constructor Food( float c, float p) { cost = c; price = p; } // Parametric constructor float CostIs() const { return cost; } //in-line inspector float PriceIs() const { return price; } //in-line inspector float Margin() const { return price/cost; } //in-line property private : float cost, price; //bad practice //see Note(1) See Notes class Drink : public Food { public : enum { small = 0, medium = 1, large = 2 }; // see Note(2) Drink( int s) { size = s; } // see Note (3) Drink( float c, float p, int s) : Food(c, p) { size = s; } // see Note(4) int SizeIs() const { return size; } float CostIs() const { // see Note(5) return ( size > small )?Food::CostIs()*1.5 : Food::CostIs(); } private : int size; using Food::Margin; //see Note(6) };

September 3, 2008 (c) Dr. David A. Workman 49

Example(continued)

(a) Allocate inherited data (cost, price) (b) Initialize inherited data by default constructor, Food::Food() (c) Allocate Drink data (size) (d) Initialize Drink data: body of constructor class Drink : public Food { public : (a) Allocate inherited data (cost, price) enum { small = 0, medium = 1, large = 2 }; Drink( int s) { size = s; } (c) Allocate Drink data (size) (d) Initialize Drink data (size): contructor initialization list // Drink( int s) : size(s){} Drink( float c, float p, int s) : Food(c, p) { size = s; } a) Allocate inherited data (cost, price) (b) Initialize inherited data by parametric constructor, Food::Food(float c, float p) (c) Allocate Drink data (size) (d) Initialize Drink data: body of constructor // Drink( float c, float p, int s) : Food(c, p), size(s) {} a) Allocate inherited data (cost, price) (b) Initialize inherited data by parametric constructor, Food::Food(float c, float p) (c) Allocate Drink data (size) (d) Initialize Drink data: constructor initialization list

September 3, 2008 (c) Dr. David A. Workman 50

Inheritance & Visibility

Class Subclass: modifier Baseclass {} Access modifier of Base class members Base class member Access specifier Public Members can be accessed by any non static member functions, friends, and other non member functions Protected Members can be accessed by any non static member functions and friends.

Private Members can be accessed by any non static member functions and by friends via protected and public member functions. To other Functions only by Public methods.

Public inheritance Members are public In the derived class. Inherited members of Baseclass are public in the Subclass Inherited members of in the Subclass ( and hidden from Subclass clients).

class. Baseclass are hidden from the Subclass ( and hidden from Subclass clients).

Protected inheritance Members are protected Baseclass are protected in the Subclass ( and hidden from Subclass clients).

Inherited members of in the Subclass ( and hidden from Subclass clients).

Hidden from derived Inherited members of class. Baseclass are hidden from the Subclass ( and hidden from Subclass clients).

Private inheritance Members are private Baseclass are hidden from the Subclass ( and hidden from Subclass clients).

from the Subclass ( and hidden from Subclass clients).

class. Baseclass are hidden from the Subclass ( and hidden from Subclass clients).

September 3, 2008 (c) Dr. David A. Workman 51

• •

Abstract vs. Concrete Classes

Abstract Classes See Notes

Are Classes for which instances can NOT be created.

A C++ class (derived class) is abstract if and only if it declares at least one pure virtual method !

Virtual Methods ( methods that will be redefined in subclasses for which dynamic binding is to be applied)

A method in the base class is declared virtual by using the following syntax:

virtual ;

A method is pure virtual if the following syntax is used

virtual = 0 ;

The “virtual” attribute is inherited when a method is redefined in a subclass.

Examples

BaseClass *p; //Static type of p is BaseClass SubClass *q; // Static type of q is SubClass p = new Subclass(); //Dynamic type of p is SubClass p->virtualmethod(); // dynamic binding is used; SubClass:: virtualmethod() is called p->ordinarymethod(); // static binding is used; BaseClass::ordinarymethod() is called, even if it is // redefined in SubClass;

September 3, 2008 (c) Dr. David A. Workman 52

Static vs. Dynamic Types

The capability to define object classes, and more importantly, inheritance hierarchies introduces new programming concepts, specifically: (1) a distinction between

static

and

dynamic types

, and (2)

polymorphism

and

runtime binding

.

See Notes!

Shape

*X;

Circle

*A ;

Quadralateral

*Q;

Rhombus

*R;

Parallelogram

*P;

Static types are declared (at compile time )and are associated with variables.

is-a

Class

Shape

(Output )

is-a if ( … )

Q =

new

Rhombus();

else

Q =

new

Parallelogram(); Q->Output();

if ( … )

X =

new

Circle();

else

X =

new

Quadralateral(); X->Output();

is-a

Class

Quadralateral

(Output) Class

Rhombus

(Output)

Dynamic types are defined at runtime and are associated with values (objects).

September 3, 2008 (c) Dr. David A. Workman Class

is-a

(Output) Class

Parallelogram Circle

(Output) 53

Polymorphism and Runtime Binding

See notes

POLYMORPHISM with DYAMIC BINDING

Polymorphism refers to operations that have multiple overriding definitions , depending on the type of object they are applied to. It is a concept very close to that of overloading . However, overriding occurs between methods in different classes related through inheritance, while overloading occurs between methods in the same class. Given a context in which polymorphism applies, two issues arise:

How to uniquely determine what definition to bind to the operation name in a given context, and

Class

Shape

(Output ) •

When to bind

a polymorphic name to a definition (compile time or runtime).

is-a is-a PROBLEM: Given the expression Output(X) , which definition of Output do we use?

Class

Quadralateral

(Output) Class

Circle

(Output)

is-a is-a ANSWER: the definition associated with the dynamic type of X. This is runtime binding!

Class

Rhombus

(Output) Class

Parallelogram

(Output) September 3, 2008 (c) Dr. David A. Workman 54

C++ Rules for Runtime Binding For the mechanism of runtime binding to apply when resolving a polymorphic method call, two conditions must be met: 1. The method must be virtual (the virtual property is inherited), and 2. The call must be made using either a pointer or a reference whose static type is a class in which the method is virtual; this class does not need be a base class.

If both of these conditions are met, then a polymorphic reference is resolved by the dynamic type of the object referenced; otherwise the static type of object pointer or reference is used to resolve the method.

September 3, 2008 (c) Dr. David A. Workman 55

Polymorphic Assignment Rule of Assignment:

the type of expression on the right-hand side of an assignment must be a subtype of

EXAMPLE

the type of the variable on the left side.

Shape

*

X, *Y; Circle

*

C ; Rhombus

*

R; X = new Quadralateral(); //OK – rule of assignment Y = new Rhombus(); //OK – rule of assignment R = Y; // Compilation error (declared type of Y // violates rule of assignment.) R = (Rhombus *) Y; // OK – explicit downcast // The compiler will generate code to check the // dynamic type of Y at runtime to ensure it // agrees with the compile-time declaration.

// If the runtime check fails, an exception // is thrown.

R = (Rhombus *) X; // Compiles OK, throws a runtime exception is-a

Class Class

Rhombus

(Output)

is-a

(Output) Class Class

Quadralateral is-a

(Output)

Shape

(Output )

Parallelogram is-a

Class

Circle

(Output) September 3, 2008 (c) Dr. David A. Workman 56

Runtime Binding of Polymorphic Methods

Pet.h

class Pet { public: Pet( string Name, string DNA, char Sex); virtual Output( ostream& fout ); protected: virtual Put( ostream& fout); private: string name; string dna; char sex; }; Cat.h

class Cat : public public: Pet { Cat( string Name, string DNA, char Sex, string Color, int Age); Output( ostream& fout ); protected: Put( ostream& fout); private: string color; int age; }; #include #include using namespace std: #include “Pet.h” #include “Cat.h” Pet{ name: Harold dna: Dog sex: Male int main(){ }Pet ofstream fout; fout.open(“Pets.out”); Pet *p = new Pet(“Harold”, “Dog”, ‘M’); Cat *calvin = new Cat(“Calvin”, “Cat”, ‘M’, “White”, 5); p->Output(fout); calvin->Output(fout); p = calvin; p->Output(fout); return 0; } Cat{ name: Calvin dna: Cat sex: Male color: White age: 5 }Cat

September 3, 2008 (c) Dr. David A. Workman 57

Pet.h

C++ Example: Class Pet

Pet.cpp

#include "Pet.h" #ifndef _PET #define _PET #include #include #include using namespace std; class Pet { public: Pet( string Name, string Dna, char Sex ); virtual void Output( ostream& fout ); protected: virtual void Put( ostream& fout ); private: string name; string dna; //name of species char };//Pet #endif sex; //'M' or 'F' or 'N' Pet::Pet( string Name, string Dna, char Sex ) { //Constructor name = Name; dna = Dna; sex = Sex; } //Pet void Pet::Output( ostream& fout ) { fout << "Pet{ "; Put( fout ); fout << "}Pet " << endl; }//Output void Pet::Put( ostream& fout ) { string sexId = (sex == 'N')? "Neutered" : ((sex == 'F')? "Female" :"Male"); fout << "name: " << name << endl; fout << " dna: " << dna << endl; fout << " sex: " << sexId << endl; }//Put

September 3, 2008 (c) Dr. David A. Workman 58

Cat.h

C++ Example: Class Cat

Cat.cpp

#include "Cat.h" #ifndef _CAT #define _CAT #include "Pet.h" class Cat: public Pet { public: Cat( string Name, string Dna, char Sex, string Color, int Age ); //Constructor virtual void Output( ostream& fout ); protected: virtual void Put( ostream& fout ); private: string color; int age; };//Cat #endif Cat::Cat( string Name, string Dna, char Sex, string Color, int Age ) : Pet(Name, Dna, Sex), color(Color) { //Constructor age = Age; } //Pet void Cat::Output( ostream& fout ) { fout << "Cat{ "; Put( fout ); fout << "}Cat " << endl; }//Output void Cat::Put( ostream& fout ) { Pet::Put(fout); fout << " color: " << color << endl; fout << " age: " << age << endl; }//Put

September 3, 2008 (c) Dr. David A. Workman 59

C++ Example: Pet Application

PetApp.cpp

#include #include using namespace std; #include "Pet.h" #include "Cat.h" int main(){ ofstream fout; fout.open("Pet.out"); Pet *p = new Pet("Harold", "Dog", 'M'); Cat *calvin = new Cat("Calvin", "Cat", 'M', "White", 5); p->Output(fout); calvin->Output(fout); p = calvin; p->Output(fout); return 0; } Pet.out

Pet{ name: Harold dna: Dog sex: Male }Pet Cat{ name: Calvin dna: Cat sex: Male color: White age: 5 }Cat Cat{ name: Calvin dna: Cat sex: Male color: White age: 5 }Cat

September 3, 2008 (c) Dr. David A. Workman 60

Static Class Members Static data members

static

[

const | volatile

]

type data_member ;

– – – –

Shared by all class instances One instance allocated in static data area and initialized at load time, or prior to execution of main().

MUST NOT be initialized by a constructor or modified by a destructor; these methods manipulate non-static data members.

MUST be initialized ONE TIME in (.cpp)(class implementation) file as follows

[ const | volatile ] type class_name ::data_member = initialization_expression ;

September 3, 2008 (c) Dr. David A. Workman 61

Static Class Members Static methods:

static type method( …) ;

– – –

Allow access to static data members!

Do not have a this pointer; cannot access non-static data members!

Called by the statement: classname :: method( ...);

– – – –

Can be called via class instances like other methods.

Can be public, protected, or private.

Can be in-line.

Cannot be const or volatile .

September 3, 2008 (c) Dr. David A. Workman 62

Storage Class Attributes Definitions

Storage class attributes are qualifiers on data (and methods) that determine where the data will be allocated, when and how it will be initialized and destroyed, and what its lifetime will be relative to the program.

extern : gives the client access to names defined in the global namespace; the scope of an extern declaration is determined by frame in which it occurs. Data in the global namespace are allocated in the static data area and initialized during execution prior to activation of main(). Their life time is the same as the program life time.

static : static global data is allocated in the static data area dedicated to transaction units and is initialized the same as global data. The difference is that static external data can only be accessed by functions and methods that have visibility into the transaction namespace. Static local data is allocated in the appropriate transaction namespace, but is not initialized until the frame that defines it is first activated. The data is accessible only while control is in that defining frame.

September 3, 2008 (c) Dr. David A. Workman 63

Storage Class Attributes Definitions(continued)

auto : this is the default storage class. Data in this category is allocated (and possibly initialized) in the runtime stack whenever the defining frame is activated. Such data is destroyed whenever control causes the defining frame to be terminated.

mutable : this category is reserved for data members that must be changed by inspector methods (const methods) of a class.

September 3, 2008 (c) Dr. David A. Workman 64

Runtime Memory Organization

Static Data Area (Literals)(Global data) (TU namespaces) (static data members of classes) Runtime stack (function & method parameters & local data) Code Segment (main) (Global Functions) (Class Bodies) Free Space Runtime heap (new)

September 3, 2008 (c) Dr. David A. Workman 65

Constructors Semantic Rules

purpose:

to initialize data members when a class instance is created Same name as class.

– –

No return type designation!

Multiple definitions are permitted so long as their signatures are unique

• •

default constructor has no parameters parameterized constructors must differ in order, number, or types of parameters

Automatically invoked by a class variable declaration or by the Object declarations create instances in the runtime stack; new in the heap.

new allocator creates instances

– –

Called for each element of an array of objects.

Constructor Execution Order:

• • •

Base class(es) initialized in declaration order Members initialized in declaration order Body of constructor is executed

Example:

Initializing a dynamic array of objects of class Person.

Person family[] = { Person("Martha",55), Person("George",58),Person("Billy",10), Person("Sally",8); };

September 3, 2008 (c) Dr. David A. Workman 66

Copy Constructors Semantic Rules

Purpose: to ensure correct copy semantics when one object is used to initialize another in the following situations:

explicit initialization in a declaration Aclass obj1; // default constructor Aclass obj2(obj1); // copy constructor Aclass obj3 = obj2; // copy constructor

an object is passed by value to a function void f( Aclass x ); // pass-by-value parameter void g( Aclass &x); // pass-by reference parameter f(obj1); // copy constructor initializes x using obj1 g(obj1); // copy constructor not called

an object is returned by value from a function Aclass p( Aclass x ) { return x;} // return-by-value Aclass& q( Aclass &x) {return x;} // return-by-reference obj2 = p(obj1); // copy constructor used to create a temp object as return value obj2 = q(obj2); // copy constructor not called - no temp object is created

Profile:

Aclass ( const Aclass& obj ) { // body } // "const" ensures initializing object is not changed

When to define:

should be explicitly defined as a public method whenever a data member is a pointer to dynamically allocated memory by non-copy constructors.

September 3, 2008 (c) Dr. David A. Workman 67

Copy Constuctor Example ( Set class )

See Notes #include using namespace std; // This class is used to model subsets of the non-negative integers.

class set0 { public: set0(); set0(const set0& obj); // default constructor 8 elements // Copy constructor (used by initialization) explicit set0(int size); ~set0(); int getCap() const { return cap; } void addMem(int x); // alternate constructor, specify set size when /= default size // destructor (used when set objects are destroyed) // In-line Inspector // add a memeber set0 operator=(set0 right); set0 operator-(); set0 operator-(set0 right); set0 operator|(set0 right); set0 operator&(set0 right); // assignment (left = right) // complement // difference // union // intersection bool isMem(int x); // membership check friend ostream& operator<<(ostream &stream, set0 obj); //stream insertion // " { e1 e2 ... en } " blank delimited values enumerated in ascending order.

}; friend istream& operator>>(istream &stream, set0 &obj);

//stream extraction

// same format as output except that elements can be given in any order!

private: int cap; // bound on the number of set elements (largest elt = cap-1) unsigned char *elts; // pointer to array of unsigned chars

;

bit "i" (from the left) = "1" means i is a member

September 3, 2008 (c) Dr. David A. Workman 68

Example ( Set class ) Copy Constructor

#include "set0.h" static unsigned char mask1[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; static unsigned char mask2[8] = {0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF }; set0::set0(){ //default constructor 8 elements

cap = 8;

elts = new unsigned char[1];

elts[0] = 0x00;

} set0::set0(const set0& obj){ //(deep) Copy constructor cap = obj.getCap();

int k = (cap+7)/8;

elts = new unsigned char[k]; for(int i = 0; i < k; i++) if( obj.isMem(i) ) addMem(i); } set0::~set0(){

//destructor cap = 0;

delete[] elts; }

mask1

and

mask2

are arrays of hexadecimal literals. 'static' limits their visibility to the file in which they are declared.

Note the use of the

new

operator to dynamically allocate an array of [?]

unsigned char

.

new

returns a pointer to this allocation.

Note that the data members of

obj

are not visible, so must call public inspector methods to get values.

Note the use of the

delete []

operator to deallocate an array. The pointer

elts

is set to the null pointer as a result.

September 3, 2008 (c) Dr. David A. Workman 69

Copy Constructor Example ( Set class )

#include "set0.h" static unsigned char mask1[8] =

{0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };

static unsigned char mask2[8] =

{0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF };

set0 set0:: operator= (set0 right) { // assignment (left = right)

cap = right.getCap(); //capacity is that of the

right

delete []elts; //destruct array of

left

elts = new unsigned char[cap]; //allocate array same size as

right

for(int i = 0; i < (cap+7)/8; i++)

// make deep copy

if( right.isMem(i) ) addMem(i);

return *this; //required for overloaded assignment operator } ostream& operator<< (ostream &stream, set0 obj) { //stream insertion

int k, x; stream << " { "; for(k = 0; k < obj.cap; k++ ){

//friends have direct visibility to data members

x = obj.elts[k/8] & mask1[k%8]; if( x != 0 ) stream << dec << k << " "; } stream << "} ";

return stream; }

September 3, 2008 (c) Dr. David A. Workman

See Notes

70

Destructors Semantic Rules

The compiler generates calls to destructors when declared objects pointers to objects) go out of scope (or declared – control leaves the frame that created them.

– – –

The compiler generates calls to destructors when the delete operator is called.

Needed to free memory allocated by constructors.

Defined in the class declaration by : ~class-name(); // NO ARGUMENTS, NO RETURN TYPE

– – – –

AT MOST ONE destructor may be defined for a class.

Destructors should be declared virtual so they will be redefined in subclasses.

Should have the same access attributes as constructors.

Can be declared in-line .

September 3, 2008 (c) Dr. David A. Workman 71

Standard Template Library (STL)

Sequence Containers: linear data structures

vector deque list //rapid insertion and deletion at back; direct access by indexing //rapid insertion and deletion at front and back; direct access by indexing.

//doubly linked; rapid access, insertion, and deletion anywhere (at any position)

Associative Containers

set multiset map multimap //rapid lookup; no duplicates //rapid lookup; duplicates allowed //key-based lookup; one-to-one mapping; no duplicates //key-based lookup; one-to-many mapping; duplicates allowed

Container Adapters

stack queue //LIFO access //FIFO access priority_queue //HPO access (Highest Priority Out)

September 3, 2008 (c) Dr. David A. Workman 72

Standard Template Library

Common member functions for all STL containers

– – – – – – – – – – – –

Default constructor Copy constructor Destructor bool empty() int max_size() operator= operator< operator> operator>= operator== operator!= swap // true if no elements, else false //maximum number of elements allowed //container assignment //binary “less than” for containers //binary “greater than” for containers //binary “greater than or equal” for containers //binary “equal” for containers //binary “not equal” for containers //swaps the elements of two containers

September 3, 2008 (c) Dr. David A. Workman 73

Standard Template Library

• – – – –

Member functions common to all FIRST-CLASS STL containers (FIRST-CLASS containers consist of all Sequential and Associatiave containers)

begin // two versions: one returns an iterator , one a const_iterator // iterators are instances of nested classes defined with the container // class; they are used to iterate over all objects held by the container // these iterators start at the “first” object held by the container

end rbegin rend // two versions corresponding to begin; these iterators return a // fictitious object just beyond the “last” object held by the container; // “reverse” interators similar to begin // “reverse” iterators similar to end erase clear // erases one or more elements from the container // erases all elements in the container leaving it “empty”.

September 3, 2008 (c) Dr. David A. Workman 74

STL Header Files

All STL classes are defined in namespace std . The header files that must be included to gain visibility are listed below.

– – – – – – – –

//contains both

queue

and

priority_queue

//contains both

map

and

multimap

//contains both

set

and

multiset

September 3, 2008 (c) Dr. David A. Workman 75

STL typedefs

All first-class containers define a common set of typedefs to make it convenient for programmers to refer to lengthy and complex type names. These can be used to declare variables, parameters and return values from functions.

value_type // the type of element stored in a container

– –

reference const_reference // a reference to the type of element stored in a container // a const reference to the type of element stored in a container; it can be used only for read and other const operations on container elements.

– – – –

pointer iterator const_iterator reverse_iterator // a pointer to the type of element stored in a container // an iterator that points to elements stored in a container // a const iterator that points to elements in a container // a reverse iterator that points to elements in a container

– –

const_reverse_iterator difference_type // a const reverse iterator that points to elements in a container // the type of result associated with operator- applied to two containers (not defined for list class and Associative containers)

size_type // the type used to count items in a non-list container via indexing operations

September 3, 2008 (c) Dr. David A. Workman 76

STL Iterators

Definition: Iterators are objects that enable the programmer to successively

access (iterate over) elements stored in a container object without having to know or use the internal data structures and organization used by the container class.

In C++, iterators are defined as nested classes within their associated container classes. Furthermore, they have exactly the same properties as pointers to container elements.

Iterator Applications

– –

Outputting all elements of a container.

Updating all elements of a container, or all elements satisfying a given condition.

– – –

Searching a container for a given element.

Deleting or removing all elements satisfying a given condition.

Sorting the elements in a container.

September 3, 2008 (c) Dr. David A. Workman 77

STL Iterators

• •

Iterator Methods for List Containers

The following methods operate on

list::interator and list::reverse_iterator * (unary dereference operator) gives access to the list element referenced by the iterator.

++ (postfix increment) advances the iterator to the next list element; (closer to end()); when the iterator is at end(), then ++ advances it to begin() -- (postfix decrement) advances the iterator to the previous list element; (closer to begin()); when the iterator is at begin(), -- advances it to end() == (iterator equality) returns true iff two iterators reference the same list element (the elements themselves may not be equal) != (iterator not equal) returns true iff two iterators do not reference the same list element.

Example

std::list listofint; std::list::iterator intiter; // create a list of integers // create an iterator for the list of integers

for( intiter = listofint.begin(); intiter < listofint.end(); intiter++ ) if ( *intiter < 0 ) cout << *intiter;

September 3, 2008 (c) Dr. David A. Workman 78

STL list Class

The list class defined in the STL is a container class that is parameterized by the type of elements it contains.

For example, its declaration has the following form:

template std::list class { … }; This syntax suggests that list is a template class defined in namespace std. It also declares that “T” is a compile-time parameter that names some existing class. “T” is not the name of an actual class, but is a compile-time variable whose value must be the name of a declared class. In class list, T denotes the type of objects that can be stored in list instances.

Example declarations of list objects:

– –

std::list< int > Inlist; // declares a list object called “Inlist” that can hold “int”s.

std::list< Shopper > Shopperlist; // a list of Shopper objects called “Shopperlist”.

September 3, 2008 (c) Dr. David A. Workman 79

STL list Class

• – – – – – – – –

Methods: in all the profiles below, T denotes the element type.

– –

list() //default constructor list(int n, const T& value = T()) //construct (n) elements all initialized to (value); //if (value) is omitted, the default constructor for //type T is called – and therefore must be defined.

T& front( ) // [!empty()] returns value at the front of the list void push_front( T e) // creates a new element at the front of the list with value e T& pop_front( ) T& back( ) void push_back( T e) // creates a new element at the back of the list with value e T& pop_back( ) bool empty( ) int size() // [!empty()] destructs the element at the front of the list // [!empty()] returns value at the back of the list // [!empty()] destructs the element at the back of the list // returns “true” if the list has at least one element // returns the number of elements in the list

September 3, 2008 (c) Dr. David A. Workman 80

STL list Class Iterator Methods: in all the profiles below, T denotes the element type.

– – – – – – – –

iterator begin() iterator end() const_iterator begin() //returns a pointer front element of list //returns a const pointer (beyond back) element of list //returns a pointer to (const front) element of list const_iterator end() //returns a const pointer (beyond back) element of list void erase( iterator pos )// [!empty()] destruct the element at (pos) void erase( iterator first, iterator last) // [!empty()] destruct the elements in [first,last).

iterator insert( iterator pos, const T& value ) // create a new element with (value) before (pos) more…

September 3, 2008 (c) Dr. David A. Workman 81

STL Examples Function to output a list with element type, T.

#include #include #include using namespace std; void output( const list listofT, ofstream& stream ){ for( list::iterator I = listofT.begin(); I != listofT.end(); I++) stream << *I << endl; // type T must overload friend “<<“ }//output

September 3, 2008 (c) Dr. David A. Workman 82

STL Examples Function to order a list with element type, T, allowing duplicates

begin() ++ - end()

#include #include #include using namespace std; void insert( list &listofT, const T& value ){ int n = listofT.size()

; if ( n == 0 ) { listofT.push_front(value); return; }else{ list::iterator i = listofT.begin(), stop = listofT.end(); for(; i != stop; i++ ) if( value < *i ){ listofT.insert( i, value ); return; } listofT.push_back(value); }//else

}//output

September 3, 2008 (c) Dr. David A. Workman 83