W 4 L 1 sh 1 LessonSubjectBook Week 4 lesson 1Class, copy-constructorH7.1-7.4; p197 – 226 Week 4...

Post on 20-Jan-2016

215 views 0 download

Transcript of W 4 L 1 sh 1 LessonSubjectBook Week 4 lesson 1Class, copy-constructorH7.1-7.4; p197 – 226 Week 4...

W 4 L 1 sh 1

Lesson Subject Book

Week 4 lesson 1 Class, copy-constructor H7.1-7.4; p197 – 226

Week 4 lesson 2 Operators 1 H8.1-8.4.2; p237 – 254

Week 5 lesson 1 Operators 2 H8.4.3-8.5; p254 – 266

Week 5 lesson 2 Inheritance H9.1-9.3; p269 – 286

Week 6 lesson 1 Virtual methods H9.5-9.8; p301 – 322 (excluding 9.6)

Week 6 lesson 2 Exceptions H10.1-10.2; p329 – 343

What is C++?

n (almost) A superset of C: (almost) every valid C program is a valid C++ program (with the same effect and efficiency).

n An OO language with classes, objects, methods, (multiple!) inheritance.

n A modern language with exceptions, templates, references.

Among the OO languages C++ is certainly: The one that can create the fastest running

applications. Not the one that allows the fastest development of

applications.

A Clock class interface

// file clock.h#ifndef CLOCK_H#define CLOCK_H

class Clock {public: // Public operations. void set (int hour, int min, int sec);  int readHour (void) { return h; } int readMin (void) { return m; } int readSec (void) { return s; }  void write (bool writeSec = true); void tick (void); private: // Internal representation of the time. int h, m, s;};

#endif

Clock

h : intm : ints : int

set(hour : int, min : int, sec : int)readHour() : intreadMin() : intreadSec() : intwrite(writeSec : boolean = true)tick()

Specification in .h file, implementation in .cpp file.

A Clock class specification

// file clock.h

#ifndef CLOCK_H#define CLOCK_H

class Clock {public: // Public operations. void set (int hour, int min, int sec);  int readHour (void) { return h; } int readMin (void) { return m; } int readSec (void) { return s; }  void write (bool writeSec = true); void tick (void); private: // Internal representation of the time. int h, m, s;};

#endif

There is no user-defined constructor: hence the compiler will define one without parameters, that does essentially nothing.

So we need an init function to set the initial values.

This is bad style, we will do better lateron.

A Clock class specification

// file clock.h#ifndef CLOCK_H#define CLOCK_H

class Clock {public: // Public operations. void set (int hour, int min, int sec);  int readHour (void) { return h; } int readMin (void) { return m; } int readSec (void) { return s; }  void write (bool writeSec = true); void tick (void); private: // Internal representation of the time. int h, m, s;};

#endif

Simple methods, that are unlikely ever to change, can be defined in the class declaration.

Parameters to C++ function (methods are functions) can have a default parameter.

Do not forget this final ‘;’ !!!

A Clock class implementation

// file Clock.cpp#include <iostream >#include <iomanip>#include ”Clock.h”

using namespace std;

// The clock is set // to the time hour:min:secvoid Clock::set ( int hour, int min, int sec){ h = hour; m = min; this->s = sec;}

Always include the definition of the class.

The function header is the same as in the .h file, except for the Clock:: before the name.

Attributes are automatically visible. You can use this->, but why clutter the code? (cpp file continues in next sheet)

// Write the time in the // format hh:mm (writeSec==true)// or hh:mm:ss (writeSec==false)void Clock::write( bool writeSec ){ cout << setw (2) << setfill ('0') << h << ':' << setw (2) << setfill ('0') << m; if (writeSec){ cout << ':' << setw (2) << setfill ('0') << s; }}

A Clock class implementation

#include <iostream >#include <iomanip>using namespace std;

Three lines needed for formatted character I/O.

(cpp file continues from previous sheet)

The default value of the parameter is NOT repeated here.

C++’s version of sprintf: just ‘shift everything into cout’.

// Advance the clock one second, 24h-stylevoid Clock::tick ( void ){ s = (s + 1) % 60; if( s == 0 ){ m = (m + 1) % 60; if( m == 0 ){ h = (h + 1) % 24; } }}

A Clock class implementation

(cpp file continues from previous sheet)

#include ”Clock.h”

void f( void ){

Clock c; c.set( 15, 50, 38 ); c.write();

Clock * pC = new Clock; pC->set(15, 55, 43); for (int i = 0; i < 33; i++) pC->tick(); pC->write();

delete pC;

}

Using the Clock class

(1) Use the class name as type in a variable declaration. The constructor is called.

Objects allocated by (2) must be deallocated explicitly.

(2) Use the new operator to allocoate a Clock on the heap. The constructor is called.

Objects allocated by (1) are deallocated implicitly. Note: NO ‘()’

class Clock {public:

// Constructors. Clock();

Clock( int hour, int min, int sec );

. . .};

Constructors

(Only) when you define none, the compiler will define a default constructor for you. It has no parameters, like this one:

Notes: you can have as many constructors as you want; constructors have no return type, not even void!

Better combine allocation and initialisation, so we can pass initialisation parameters to the constructor.

Clock::Clock( void ){ h = m = s = 0;} Clock::Clock( int hour, int min, int sec ){ h = hour; m = min; s = sec;}

Constructors - implementation

Constructor implementation, using assignments.

Alternative, using the int constructors in the initializer list.

This is the preferred way: Efficient. Can be used with constants. Can be used when no default

constructor is available.

Clock::Clock( int hour, int min, int sec ): h(hour), m(min), s(sec){}

class Clock {public: Clock (); Clock ( int hour, int min, int sec );};

Constructors – use defaults!

Why write both(+ implementations)?

When you can have the same effect with this:

class Clock {public: Clock ( int hour = 0, int min = 0, int sec = 0 ): h(hour), m(min), s(sec) {}};

This effectively defines initializers with zero, one, two, and three parameters.

 Clock c1;Clock c2(12);Clock * pC1 = new Clock(15,45);Clock * pC2 = new Clock(16,10,15);

c1.write();c2.write();pC1->write();pC2->write();

Using the constructors

00.00.0012.00.0015.45.0016.10.15

On the stack

On the heap

An object can be an attribute

Clock

h : intm : ints : int

set(hour : int, min : int, sec : int)readHour() : intreadMin() : intreadSec() : intwrite(writeSec : boolean = true)tick()

Flight

no : char *

Flight()Flight(flightNo : char *, depH : int, depM : int, arrH : int, arrM : int)Flight(flightNo : char *, depT : Clock, arrT : Clock)Flight(f : const Flight &)~Flight()init(flightNo : char *, depH : int, depM : int, arrH : int, arrM : int)delay(min : int)writeInfo()

+dep +arr

This is called Compostition, somtimes Composition-aggregation

A copy constructor

A constructor with its class type as argument, but const &, is called a copy-constructor.

This copy-constructor is called:

When an explicit copy is constructed

When a parameter is passed by value

When a class object is returned

Flight( const Flight & f );

Flight k(f);Flight k = f;

Flight (char * nr, Clock dep, Clock arr )

Clock f( void ){ Clock c; . . . return c;}

Why this ‘&’ ?

This is not an assignment!

(note: NOT for an assignment!)

The default copy constructor

When you don’t define a copy constructor, the compiler will define one.

This default copy constructor will: Call the copy constructor for each attribute (with the

value of the current attribute). Build-in types like char, int, float, struct, and pointers

have copy constructors that behave like their assignment operators: they do a bit-wise copying from the source to the destination.

Flight class definition : destructor

A destructor is called automatically:

When an object leaves scope.

When an object is disposed.

class Flight {public: // Constructors. Flight(){ no = new char [1]; no[0] = '\0'; } Flight( char flightNo[], int depH, int depM, int arrH, int arrM ); Flight( char flightNo[], Clock depT, Clock arrT );  // Copy constructor Flight( const Flight & f );  // Destructor ~Flight () { delete [] no; }  // Public operations. void init( char flightNo[], int depH, int depM, int arrH, int arrM ); void delay( int min ); void writeInfo( void ); private: // Internal representation of a flight. char * no; Clock dep, arr;};

Flight class - constructors

Array new

Why +1 ??

Flight::Flight(){ no = new char [1]; no[0] = '\0'; }

Flight::Flight( char flightNo[], int depH, int depM, int arrH, int arrM): dep( Clock( depH, depM, 0 ) ), arr( Clock( arrH, arrM ) ){ no = new char [ strlen( flightNo ) + 1 ]; strcpy( no, flightNo );}

Flight::Flight( char flightNo[], Clock depT, Clock arrT ): dep( depT ), arr( arrT ){ no = new char[ strlen( flightNo ) + 1 ]; strcpy( no, flightNo );}

Construct clocks, pass them

Pass the clocks we got

Error?

Flight class – init, delay

void Flight::init( char flightNo[], int depH, int depM, int arrH, int arrM ){ no = new char[ strlen( flightNo ) + 1 ]; strcpy ( no, flightNo ); dep.set( depH, depM, 0 ); arr.set( arrH, arrM );} void Flight::delay( int min ){ for( int i = 1; i <= min * 60; i++ ){ dep.tick (); } for( int j = 1; j <= min * 60; j++ ){ arr.tick (); }}

Why not simplyvoid Flight::init( char flightNo[], int depH, int depM, int arrH, int arrM ){ no = flightNo; dep.set( depH, depM, 0 ); arr.set( arrH, arrM );}

copy constructor (wrong)

Flight::Flight( const Flight & f ) : dep( f.dep ), arr( f.arr ), no( f.no ){}

This is what the default copy constructor would do too.

Flight f("SK1853", 8, 10, 10, 55);

Flight g(f);

Let’s create a flight f,

and a copy of it called g.

This is what we get (a shallow copy).

Two problems: Changing a flight’s name Dealocation

copy constructor (good)

Flight::Flight( const Flight & f ) : dep( f.dep ), arr( f.arr ){ no = new char[ strlen( f.no ) + 1 ]; strcpy( no, f.no );}

Allocate a new string, copy the content.

Now we get real

individuals, not a Borg (deep copy).

Consequences of a pointer attribute

Whenever you have a pointer attribute, you almost certainly need:

A constructor that initializes the pointer; each constructor must do so.

A copy constructor that creates a deep copy. A destructor. (next lesson) an assignment operator.