an introduction to c++ cop 4331: oo processes for software development © dr. david a. workman...
TRANSCRIPT
An Introduction to C++
COP 4331: OO Processes for Software Development© Dr. David A. Workman
School of EE and Computer ScienceUniversity of Central Florida
January 19, 2007September 3, 2008
September 3, 2008 (c) Dr. David A. Workman 2
Getting StartedThe UNIX C++ Environment
C++Source Files
C++Object
Files (.o)
g++Compiler
Your C++ WorkingDirectory
Header-files.hSource-files.cpp
.h files contain module interfaces
.cpp files contain moduleimplementation details
The program entry point is the main() function thatmust be defined in a .cpp file.
>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 compilationmessages. (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.
September 3, 2008 (c) Dr. David A. Workman 3
C++ Program Organization
Main()
AppProgram.cpp
Header File
ImplementationFile
ClassA.h
ClassA.cpp
Header File
ImplementationFile
ObjectX.h
ObjectX.cpp
Header File
ImplementationFile
IOMgmt.h
IOMgmt.cpp….
Organization Principle: All C++ programs should consist of a (.cpp)file holding the main() function together witha 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
September 3, 2008 (c) Dr. David A. Workman 4
C++ Organization (contd)
#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;}
Example.cpp
#include "Alpha.h"Alpha::Alpha() //Constructor{}
void Alpha::Extract( ifstream& fin) throw(TokenError) //procedure{ if( … ) throw TokenError( "Bad Syntax", "Alpha::Extract()");}…
#ifndef _ALPHA#define _ALPHA//includes go hereclass Alpha{ public: Alpha(); void Extract( ifstream& fin) throw(TokenError); … private: // declare data members here};#endif
Alpha.h
Alpha.cpp
Class Module
September 3, 2008 (c) Dr. David A. Workman 5
C++ Organization (contd)
#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;}
Example.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) }
… bodies of other functions and procedures of Beta
}
#ifndef _BETA#define _BETA//includes go herenamespace Beta{ void Initialize(); // other function and procedure declarations …}#endif
Beta.h
Beta.cpp
Single ObjectModule(namespace)
For other examples of Single Object namespaces, see IOMgmt::FileParser & IOMgmt::Concordance
September 3, 2008 (c) Dr. David A. Workman 6
C++ Organization (contd)
NamespaceModule
(see IOMgmt)
IOMgmt
InMgrOutMgr
TokenError IOError
AppError
StringTokenizerTokenizer Not used in this course.
September 3, 2008 (c) Dr. David A. Workman 7
Unix Make Utility Program
makefilemake
Your C++ WorkingDirectory
C++SourceFiles
(.h, .cpp)
C++Object(.o)
Files
ExecutableFile
(a.out)
September 3, 2008 (c) Dr. David A. Workman 8
Make Files
# makefile for foo_to_v5d.c conversion program (this is a comment)PROGRAM = lab_2CFLAGS = -cCC = g++LIBS = -lmOBJECTS = $(PROGRAM).o file1.o file2.o … filek.o
$(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
# introduces comments
Identifier : introduces a ruleFile0: File1 File2 … Filek command
SeeNotes
To "run" a makefile :>makeor >make -f makefile-name
identifier = declarations
September 3, 2008 (c) Dr. David A. Workman 9
Makefile Example
simapp.cpp
simmodels.hsimmodels.cpp
simmgmt.hsimmgmt.cpp
iomgmt.hiomgmt.cpp
apperror.happerror.cpp
Includes
Includes
Includes
Includes
includes
includes
includes
includes
Compilation Dependency Graph
September 3, 2008 (c) Dr. David A. Workman 10
Makefile Example
simapp: simapp.o simmodels.o simmgmt.o iomgmt.o apperror.og++ -l m -o simapp simapp.o simmodels.o simmgmt.o iomgmt.o apperror.o
apperrors.o: apperror.cpp apperror.hg++ -c apperror.cpp
iomgmt.o: iomgmt.cpp iomgmt.h apperror.hg++ -c iomgmt.cpp
simmgmt.o: simmgmt.cpp simmgmt.h iomgmt.h apperror.hg++ -c simmgmt.cpp
simmodels.o: simmodels.cpp simmodels.h simmgmt.h iomgmt.h apperror.hg++ -c simmodels.cpp
simapp.o: simapp.cpp simmodels.h simmgmt.h iomgmt.h apperror.hg++ -c simapp.cpp
executable Link in Math library Name of the
executable
Names of object files needed to create executable
September 3, 2008 (c) Dr. David A. Workman 11
C++ Example
#include <iostream> #include <iomanip> // format manipulator operations with parms#include <string> // string classusing namespace std; // using directive for standard C++ namespace
void Get_Text( string& Data ); // global function declarationint 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}
info1.cpp
SeeNotes
September 3, 2008 (c) Dr. David A. Workman 12
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 i = 0; i < 3; i++) Get_Text(Address[i]); // cin >> Address[i];// Always end your programs with a EOL to clear the system output buffer// before returning to the OS. cout << '\n'; // cout << endl;
September 3, 2008 (c) Dr. David A. Workman 13
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 IOC++ supports stream IO on external files. You must #include <fstream> to use these features.
• EXCEPTIONSExceptions 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 SPACESName 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 14
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 Cstruct t { int x; float y;}; // type is (struct t)struct t A; // variable of type (struct t)A.x = 5; // component reference
Example. In C++struct t { int x; float y;}; t A; // “struct” no longer requiredA.x = 5;
C++ unions and enumsare similar to
structs and classes
September 3, 2008 (c) Dr. David A. Workman 15
Pointers and ReferencesDefinitions
– 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.
Examplesint 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 16
#include <iostream>#include <fstream>using namespace std;const int cutoff = 6000;const float rate1 = 0.3;const float rate2 = 0.6;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; }//while fin.close(); // close file objects fout.close(); return 0;}
SeeNotesFile IO
September 3, 2008 (c) Dr. David A. Workman 17
#include <fstream>#include <string>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" << " Tax: " << (int) tax*100.0 << " Lepta" << endl; }//while fin.close(); // close file objects fout.close(); return 0;}
File IOSee
Notes
September 3, 2008 (c) Dr. David A. Workman 18
Definitionclass typename {
private data and function members // default visibility [ access-specifier : data and function members ]+
} [ object-list ];– A class introduces a new encapsulated type, typename. – Access-specifier determines visibility of declared data and function
members• private = visible only to the class methods and friend functions• protected = visible to methods of any subclass (derived class)• public = visible anywhere the class is visible.• Default access 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.
ClassesSee Notes Page
September 3, 2008 (c) Dr. David A. Workman 19
ClassesSemantic 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 ), … { … }b) Required to initialize (non-static) const data members or data members of some
class type.
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.
Initialization List: between colon and {
September 3, 2008 (c) Dr. David A. Workman 20
Class Definition Example
#include <string>using namespace std;class Person { string name; // private data member (instance of class string) int age; // private data member float salary; // private data memberpublic: 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) };
“Person.h”
NOTES:(1) A class declaration should be defined in a header file.(2) 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.(3) A const method cannot change data members unless they have been declared mutable.(4) 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 definedin the implementation file (.cpp file)!
See Notes Page
September 3, 2008 (c) Dr. David A. Workman 21
Class Implementation Example
#include <string> //redundant – included by Person.h below.using namespace std;#include "Person.h"Person::Person( string s, int a ) { // public constructor (creates instances) name = s; age = a; salary = 0.0;}
Person::~Person() { // public destructor (reclaims instance memory)}
void Person::GetOlder() { // public mutator age += 1;}
void Person::GetRaise( float amount ) { // public mutator salary += amount;}
“Person.cpp” Constructor requires two parameters.Default constructor NOT defined.
Destructor is the “default”. It simplydeallocates instance memory AFTERcalling the destructors for any datamembers that are instances of otherclasses (e.g. name )
Mutators change instance attributes.References to data members arecomponents of the instance to whichthe method is called.
See Notes
September 3, 2008 (c) Dr. David A. Workman 22
Class Client
#include <string>#include <iostream>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’;}
Class Design Principles1. 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 overloadedExtract() 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 designconstraints for the class. An exception should be thrown by any method that finds the instance state to beincompatible 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 anexception 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 shouldbe 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.
September 3, 2008 (c) Dr. David A. Workman 24
ExceptionsBasic 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 25
Exceptions: Design Principles1. 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.
2. 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 togive users and developers the most information possible about the cause of the exception andthe conditions exiting at the time the exception occurs.
3. An exception should be propagated up the call chain to some method (or methods) having themost information to decide how the exception should be handled (recovery or termination).
September 3, 2008 (c) Dr. David A. Workman 26
Example: Exceptions
#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}
Each class is always responsible for checking forerroneous conditions andthrowing exceptions whenthey occur.
Stack.h
#include “Stack.h”Stack::Stack(){ // constructor contents = new int[10]; topidx = -1;}
Stack::~Stack(){ // destructor needed delete [] contents;}
void Stack::push( int x) throw(AppError) { if ( topidx >= 9 ) throw AppError("Stack Overflow"); contents[++topidx] = x;}
int Stack::pop() throw(AppError) { if (topidx < 0 ) throw (char *) “Stack Underflow” ; return contents[topidx--];}
bool Stack::empty(){ return topidx < 0;}
Stack.cpp
Throw clauses must agree in header and implementation files
Header file name should NOT be different from class name.
Exception of typeAppError
Exception of type(char *)
September 3, 2008 (c) Dr. David A. Workman 27
Example: Exceptions#include <iostream>#include <string>using namespace std;#include “Stack.h”#include "AppError.h"int main( ) { Stack s; int x; bool more; 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 if ( !more ) break; }//try catch (AppError msg){ cout << msg.getMsg() << endl; cout << “Stack Contents: “ << endl; while( !s.empty() ) cout << s.pop() << endl; return 1; } //catch
}//forreturn 0;}// main
File 1(Stack Client)
Client code is always Responsible for detectingAnd handling exceptions.
catch (…){ // handles any exception cout << “Unknown Exception!” << endl; return 1;}//The default handler should always//be placed last among handlers
September 3, 2008 (c) Dr. David A. Workman 28
Name SpacesDefinition
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 29
Namespaces
USES1. 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 30
Name Spaces
Global Namespace
NamedNamespace
TranslationUnit
Namespace(one per file)
NamedNamespace
NamedNamespace …
TranslationUnit
Namespace(one per file)
TranslationUnit
Namespace(one per file)
…
See Notes
September 3, 2008 (c) Dr. David A. Workman 31
Named namespaces
namespace alpha {int One;typedef int *INTPTR;INTPTR copyint( int value ) { One = value; INTPTR p = new int(One); return p;}//copyint
}//alpha
int main() { alpha::INTPTR p;int x = 25;p = alpha::copyint(x);}
One fileThe namespace “alpha” isdirectly visible – it is declaredin the global namespace.
Names defined within alpha must bereferenced using the scope resolutionoperator (::), since they are not directly (globally) visible.
September 3, 2008 (c) Dr. David A. Workman 32
Named namespaces
Three files#ifndef ALPHA#define ALPHAnamespace alpha {extern int One; //data declarationtypedef int *INTPTR;INTPTR copyint( int value ); //fn decl.}//alpha#endif
alpha.h
#include "alpha.h"int main() { alpha::INTPTR p,q;int x = 25;p = alpha::copyint(x);q = alpha::copyint(alpha::One);}
NOTE: The 3-file approach is preferred.
#include “alpha.h”namespace alpha {int One; //data definitiontypedef int *INTPTR;INTPTR copyint( int value ) { //fn defn One = value; INTPTR p = new int(One); return p;}//copyint
}//alpha
alpha.cpp
September 3, 2008 (c) Dr. David A. Workman 33
Namespace Extension
#include <iostream>#include <string>using namespace std;#include alpha.hvoid 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}
#include <iostream>#include <string>using namespace std;
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
//code that uses the local extensions to alpha
File1.cpp File2.cpp
An extensionto alphaLocal toFile2.cpp
See Notes Page
File2.cpp
Namespace Extension
September 3, 2008 (c) Dr. David A. Workman 34
#ifndef ALPHA#define ALPHAnamespace alpha { extern int One; //data declaration typedef int *INTPTR; INTPTR copyint( int value ); //fn decl.
extern float Two; //data declaration typedef int *FLTPTR; FLTPTR copyflt( float value ); //fn decl.}//alpha
#endif
Alpha.hAny other files that need to referenceInformation defined in namespace AlphaOnly need to include “Alpha.h” to gainuse of features contributed by both File1.cppand File2.cpp
September 3, 2008 (c) Dr. David A. Workman 35
TU namespaces
#include <iostream>#include <string>#include <math>using namespace std;extern double pi; //defined in another filedouble h( double ), h2(double);namespace { // scope limited to this file double f( double x) { return x * sqrt(x) } //f}//namespacedouble g(double x){ // global namespace return sqrt(x)/x;}//g
int main() { double y = 25.0*pi; cout << “y^1.5 = “ << f(y) << endl; cout << “y^-0.5 = “ << g(y) << endl;}// main
double g( double ); // refers to g in file 1namespace { // visible to h() and h2() const double pi = 3.1415926; double f( double x) { return x * g(x); }//f}//TU namespace
double h( double y) { return y/f(y);}//h
double h2( double y){ return pi*y*g(y);}//h2
See Notes Page
File1.cppFile2.cpp
This “pi” hides “::pi”and is only visible in File2.
Refers to the local “pi” not “::pi”
September 3, 2008 (c) Dr. David A. Workman 36
Namespace declarations and directives
• Using DeclarationsA using declaration adds a specific name declared in a namespace to the local frame
where the using declaration is specified.
• Using DirectiveA 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 Zint 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 ...}
namespace beta { int X, Y,Z; }int Z; // global Zint 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 ...}
September 3, 2008 (c) Dr. David A. Workman 37
Namespace Aliases
namespace beta { int X, Y,Z; namespace delta { float X,Y,Z; } }int Z; // global Znamespace D = beta::delta; //alias declarationsint 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}
namespace alias-name = namespace-id ;
September 3, 2008 (c) Dr. David A. Workman 38
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 39
Namespaces as Single Objects
#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.h
#include “Object.h”namespace Object {
}
Object.cpp
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 anyother methods.
Define the bodies of the functions declared in the header file. The bodies are defined usingThe 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 40
Namespaces as Single Objects
#ifndef _CONCORD#define _CONCORD
#include <iostream>#include <fstream>using namespace std;
#include "Word.h"#include "Reference.h"
namespace Concordance { void AddWordRef( Word& Wrd, Reference& Ref); void Output( ostream& fout);}#endif
#include <list>using std::list;#include "Concordance.h"#include "Entry.h"
namespace Concordance { list<Entry> Contents; void AddWordRef( Word& Wrd, Reference& Ref) { for (list<Entry>::iterator I = Contents.begin(); I != Contents.end(); I++) { if( Wrd < I->GetKey() ) {Contents.insert(I,Entry(Wrd,Ref)); return;} if( Wrd == I->GetKey() ) {I->AddRef(Ref); return; } }//for Contents.push_back(Entry(Wrd,Ref)); }//AddWordRef
void Output( ostream& fout) { for(list<Entry>::iterator I = Contents.begin(); I != Contents.end(); I++) I->Output(fout);
}//Output}//Concordance
Concordance.h Concordance.cpp
#include "Word.h"#include "Reference.h"#include "Concordance.h"int main(){ Word aword; Reference aref; Concordance::AddWordRef(aword,aref); Concordance::Output( cout );}
Client Code
September 3, 2008 (c) Dr. David A. Workman 41
Figure 2
#include “Object.h”
int main(){ …. Object::Initialize(); // Call Object initialization fn … Object::Function1(…); // Call Object procedure … x = Object::Function2(…); // Call Object function
}
Team Development with Namespaces
September 3, 2008 (c) Dr. David A. Workman 42
SystemX
SubA
SubB
Class One
Class Two
Main
Team1
TeamA
TeamB
Team Development with Namespaces
September 3, 2008 (c) Dr. David A. Workman 43
SubA
TeamA:TedSallyFred
SubA.h
Contains all public declarations fornamespace SubA. This is used byclients of SubA (other teams) as well as members of Team A.
#include “SubA.h”using namespace SubA;#include “SubB.h”namespace SubA{ //Ted’s Code
}
Ted.h
Ted.cpp
Contains alland only theinformationTed needs tomake public(for other teams and/or other team members)
September 3, 2008 (c) Dr. David A. Workman 44
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 the subclass– public members 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 45
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 46
SubtypesDefinition: Type S is a subtype of T, if every legitimate value of S is also a
legitimate value of T ( “is a” relation)
In UML the “IS-A” relation ismeant to model the subtyperelation between two classes.
UCFstudent
Attributes1
Methods1
CSmajor
Attributes1Attributes2
Methods1Methods2
Inheritance
An instance of CSmajor inherits the characteristics(attributes) and behavior (methods) of its superclassUCFstudent. 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.
IS-A
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)
Attributes andbehaviors unique toCSmajors
Reference: Object-Oriented Software Development Using Java, 2nd Ed., by Xiaoping Jia, Addison-Wesley, ISBN = 0-201-73733-7
September 3, 2008 (c) Dr. David A. Workman 47
Overriding vs Overloading MethodsDefinition: 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: stl::list<Point> vertices; public: Shape(); //default constructor Shape( ifstream& fin); Shape( stl::list<Point> 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(); };
Instance of Overloading(operations on the same subtype)(same name, different profiles)
Instances of Overriding(operations on different subtypes)(same name, same profiles)
September 3, 2008 (c) Dr. David A. Workman 48
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, 2nd Ed., by Xiaoping Jia, Addison-Wesley, ISBN = 0-201-73733-7
September 3, 2008 (c) Dr. David A. Workman 49
Example: Subclasses & Inheritanceclass 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)};
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)};
SeeNotes
September 3, 2008 (c) Dr. David A. Workman 50
Example(continued)
class Drink : public Food { public: enum { small = 0, medium = 1, large = 2 }; Drink( int s) { size = s; } //Drink( int s) : size(s){} Drink( float c, float p, int s) : Food(c, p) { 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 default constructor, Food::Food()(c) Allocate Drink data (size)(d) Initialize Drink data: body of constructor
(a) Allocate inherited data (cost, price)(b) Initialize inherited data by default constructor, Food::Food()(c) Allocate Drink data (size)(d) Initialize Drink data (size): contructor initialization list
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
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 51
Inheritance & Visibility
Base class member Access specifier
Public inheritance
Protected inheritance
Private inheritance
Public Members can be
accessed by any non-static member
functions, friends, and other non-
member functions
Members are public In the derived class.
Members are protected In the derived class.
Members are private In the derived class.
Protected Members can be
accessed by any non-static member functions and
friends.
Members are protected In the derived class.
Members are protected In the derived class.
Members are private In the derived class.
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.
Hidden from derived class.
Hidden from derived class.
Hidden from derived class.
Access modifier ofBase class members
Class Subclass: modifier Baseclass {}
Inherited members ofBaseclass are public inthe Subclass
Inherited members ofBaseclass are protected in the Subclass ( andhidden from Subclass clients).
Inherited members ofBaseclass are hidden from the Subclass ( and hiddenfrom Subclass clients).
Inherited members ofBaseclass are protected in the Subclass ( andhidden from Subclass clients).
Inherited members ofBaseclass are hidden from the Subclass ( and hiddenfrom Subclass clients).
Inherited members ofBaseclass are protected in the Subclass ( andhidden from Subclass clients).
Inherited members ofBaseclass are hidden from the Subclass ( and hiddenfrom Subclass clients).
Inherited members ofBaseclass are hidden from the Subclass ( and hiddenfrom Subclass clients).
Inherited members ofBaseclass are hidden from the Subclass ( and hiddenfrom Subclass clients).
September 3, 2008 (c) Dr. David A. Workman 52
Abstract vs. Concrete Classes• Abstract Classes
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 subclassesfor which dynamic binding is to be applied)
A method in the base class is declared virtual by using the following syntax:virtual <function declaration>;
A method is pure virtual if the following syntax is usedvirtual <function declaration> = 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;
See Notes
September 3, 2008 (c) Dr. David A. Workman 53
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.
Shape *X;Circle *A ;Quadralateral *Q;Rhombus *R;Parallelogram *P;
if ( … ) Q = new Rhombus(); else Q = new Parallelogram();Q->Output();if ( … ) X = new Circle(); else X = new Quadralateral();X->Output();
Static types are declared(at compile time )and are associated with variables.
Dynamic types are definedat runtime and are associatedwith values (objects).
Class Circle(Output)
Class Shape (Output )
Class Quadralateral(Output)
Class Parallelogram(Output)
Class Rhombus(Output)
is-ais-a
is-ais-a
See Notes!
September 3, 2008 (c) Dr. David A. Workman 54
Polymorphism and Runtime BindingPOLYMORPHISM 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
• When to bind a polymorphic name to a definition (compile time or runtime).
PROBLEM: Given the expressionOutput(X) , which definition of Output do we use?
ANSWER: the definition associated withthe dynamic type of X. This is runtimebinding!
Class Circle(Output)
Class Shape (Output )
Class Quadralateral(Output)
Class Parallelogram(Output)
Class Rhombus(Output)
is-ais-a
is-ais-a
See notes
September 3, 2008 (c) Dr. David A. Workman 55
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 56
Polymorphic AssignmentRule of Assignment:
the type of expression on the right-hand side of an assignment must be a subtype of the type of the variable on the left side.
Class Circle(Output)
Class Shape (Output )
Class Quadralateral(Output)
Class Parallelogram(Output)
Class Rhombus(Output)
is-ais-a
is-ais-a
EXAMPLE
Shape *X, *Y;Circle *C ;Rhombus *R;X = new Quadralateral(); //OK – rule of assignmentY = new Rhombus(); //OK – rule of assignmentR = 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
September 3, 2008 (c) Dr. David A. Workman 57
Runtime Binding of Polymorphic Methods
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;};
class Cat : public Pet { public: Cat( string Name, string DNA, char Sex, string Color, int Age); Output( ostream& fout ); protected: Put( ostream& fout); private: string color; int age;};
#include <iostream>#include <fstream>using namespace std:#include “Pet.h”#include “Cat.h”int main(){ 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;}
Pet.h
Cat.h
Pet{ name: Harold dna: Dog sex: Male}Pet
Cat{ name: Calvin dna: Cat sex: Male color: White age: 5}Cat
September 3, 2008 (c) Dr. David A. Workman 58
C++ Example: Class Pet
#ifndef _PET#define _PET#include <string>#include <iostream>#include <fstream>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 sex; //'M' or 'F' or 'N'};//Pet#endif
#include "Pet.h"
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
Pet.h Pet.cpp
September 3, 2008 (c) Dr. David A. Workman 59
C++ Example: Class Cat
#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
#include "Cat.h"
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
Cat.h Cat.cpp
September 3, 2008 (c) Dr. David A. Workman 60
C++ Example: Pet Application
#include <iostream>#include <fstream>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{ 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
PetApp.cpp Pet.out
September 3, 2008 (c) Dr. David A. Workman 61
Static Class MembersStatic 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 62
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 63
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 64
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 65
Runtime Memory Organization
CodeSegment(main)
(Global Functions)(Class Bodies)
Static Data Area(Literals)(Global data)
(TU namespaces)(static data members of classes)
Runtime stack(function & method
parameters & local data)
Runtime heap(new)
Free Space
September 3, 2008 (c) Dr. David A. Workman 66
ConstructorsSemantic 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 new allocatorObject declarations create instances in the runtime stack; new creates instances in the heap.
– 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 67
Copy ConstructorsSemantic Rules
Purpose: to ensure correct copy semantics when one object is used to initialize another in the following situations:
• explicit initialization in a declarationAclass obj1; // default constructorAclass obj2(obj1); // copy constructorAclass obj3 = obj2; // copy constructor
• an object is passed by value to a functionvoid f( Aclass x ); // pass-by-value parametervoid g( Aclass &x); // pass-by-reference parameter f(obj1); // copy constructor initializes x using obj1g(obj1); // copy constructor not called
• an object is returned by value from a functionAclass 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 valueobj2 = q(obj2); // copy constructor not called - no temp object is created
Profile: Aclass ( const Aclass& obj ) { // "const" ensures initializing object is not changed // body }
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 68
Copy ConstuctorExample ( Set class )
#include <iostream>using namespace std;// This class is used to model subsets of the non-negative integers.class set0 { public: set0(); // default constructor 8 elements set0(const set0& obj); // Copy constructor (used by initialization) explicit set0(int size); // alternate constructor, specify set size when /= default size ~set0(); // destructor (used when set objects are destroyed) int getCap() const { return cap; } // In-line Inspector void addMem(int x); // add a memeber set0 operator=(set0 right); // assignment (left = right) set0 operator-(); // complement set0 operator-(set0 right); // difference set0 operator|(set0 right); // union set0 operator&(set0 right); // 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};
SeeNotes
September 3, 2008 (c) Dr. David A. Workman 69
Copy ConstructorExample ( 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(){ //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 arearrays of hexadecimalliterals. 'static' limitstheir visibility to thefile in which they aredeclared.
Note the use of the newoperator to dynamicallyallocate an array of [?]unsigned char. new returns a pointer to thisallocation.
Note the use of the delete []operator to deallocate an array. The pointer elts is set to the null pointer as aresult.
Note that the data members of objare not visible, so must call publicinspector methods to get values.
September 3, 2008 (c) Dr. David A. Workman 70
Copy ConstructorExample ( 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;}
SeeNotes
September 3, 2008 (c) Dr. David A. Workman 71
Destructors
Semantic Rules– The compiler generates calls to destructors when declared objects (or declared
pointers to objects) go out of scope – 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 72
Standard Template Library (STL)
• Sequence Containers: linear data structuresvector //rapid insertion and deletion at back; direct access by indexingdeque //rapid insertion and deletion at front and back; direct access by
indexing.list //doubly linked; rapid access, insertion, and deletion
anywhere (at any position)
• Associative Containersset //rapid lookup; no duplicatesmultiset //rapid lookup; duplicates allowedmap //key-based lookup; one-to-one mapping; no duplicatesmultimap //key-based lookup; one-to-many mapping; duplicates allowed
• Container Adaptersstack //LIFO accessqueue //FIFO accesspriority_queue //HPO access (Highest Priority Out)
September 3, 2008 (c) Dr. David A. Workman 73
Standard Template Library
• Common member functions for all STL containers– Default constructor
– Copy constructor
– Destructor
– bool empty() // true if no elements, else false
– int max_size() //maximum number of elements allowed
– operator= //container assignment
– operator< //binary “less than” for containers
– operator> //binary “greater than” for containers
– operator>= //binary “greater than or equal” for containers
– operator== //binary “equal” for containers
– operator!= //binary “not equal” for containers
– swap //swaps the elements of two containers
September 3, 2008 (c) Dr. David A. Workman 74
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 // two versions corresponding to begin; these iterators return a // fictitious object just beyond the “last” object held by the
container;– rbegin // “reverse” interators similar to begin– rend // “reverse” iterators similar to end– erase // erases one or more elements from the container– clear // erases all elements in the container leaving it “empty”.
September 3, 2008 (c) Dr. David A. Workman 75
STL Header Files
• All STL classes are defined in namespace std. The header files that must be included to gain visibility are listed below.
– <vector>
– <list>
– <queue> //contains both queue and priority_queue
– <deque>
– <stack>
– <map> //contains both map and multimap
– <set> //contains both set and multiset
– <bitset>
September 3, 2008 (c) Dr. David A. Workman 76
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 // a reference to the type of element stored in a container
– const_reference // 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 // a pointer to the type of element stored in a container
– iterator // an iterator that points to elements stored in a container
– const_iterator // a const iterator that points to elements in a container
– reverse_iterator // a reverse iterator that points to elements in a container
– const_reverse_iterator // a const reverse iterator that points to elements in a container
– difference_type // 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 77
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 78
STL Iterators
• Iterator Methods for List ContainersThe 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.
• Examplestd::list<int> listofint; // create a list of integers
std::list<int>::iterator intiter; // 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 79
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 <class T> 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 80
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( ) // [!empty()] destructs the element at the front of the list
– T& back( ) // [!empty()] returns value at the back of the list
– void push_back( T e) // creates a new element at the back of the list with value e
– T& pop_back( ) // [!empty()] destructs the element at the back of the list
– bool empty( ) // returns “true” if the list has at least one element
– int size() // returns the number of elements in the list
September 3, 2008 (c) Dr. David A. Workman 81
STL list Class• Iterator Methods: in all the profiles below, T denotes the element type.
– iterator begin() //returns a pointer front element of list
– iterator end() //returns a const pointer (beyond back) element of list
– const_iterator begin() //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 82
STL Examples
Function to output a list with element type, T.#include <iostream>
#include <fstream>
#include <list>
using namespace std;
void output( const list<T> listofT, ofstream& stream ){for( list<T>::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 83
STL Examples
Function to order a list with element type, T, allowing duplicates
#include <iostream>#include <fstream>#include <list>using namespace std;
void insert( list<T> &listofT, const T& value ){ int n = listofT.size(); if ( n == 0 ) { listofT.push_front(value); return; }else{ list<T>::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
begin()
end()
++
--