classes. class expanded concept of a data structure: instead of holding only data, it can hold both...

22
Classes

Upload: esther-barton

Post on 22-Dec-2015

218 views

Category:

Documents


0 download

TRANSCRIPT

Classes

Class

expanded concept of a data structure: instead of holding only data, it can hold both data and functions.

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

Usually class’s declarations will be in .h file, while its implementation will be in the .cpp file.

Define a plant

class Plant

{

private:

bool hasLeaves;

double height;

};

clas

s bo

dy access control

Data Members

Do we have a plant yet ? NO !!! We have a plan for a plant

"Plant.h"

Create a plant

#include "Plant.h"

int main()

{

Plant myPlant;

}

Only after that line we have a plant !

“main.cpp"

What does this plant look like?

?

Did we initialized the members ? NO !!!

Lets see what happened…

WE DO NOT KNOW

Construction

Plant myPlant;

When we create an instance of a class – a constructor called.

When we do not define any – a default constructor is created by

the compiler.

class Plant

{

public:

Plant() { }

private:

bool hasLeaves;

double height;

};

But… It’s empty!!!

Well – not exactly.It creates the members :• First : hasLeaves• Second: height

Did we initialized the members ? NO !!!

double and bool types contain TRASH by default

Construction

class Plant

{

public:

Plant() : hasLeaves( true ), height( 1 ) { } private:

bool hasLeaves;

double height;

};

Constructor is a special function of a class.• It’s name is the same as the class name.• It has no return value• It allows members initialization – when they

are created. Like that:

Now we KNOW:when we create a plant like this:Plant myPlant;We have a plant of height 1, and with leaves.

Construction

class Plant

{

public:

Plant() : hasLeaves( true ), height( 1 ) { } Plant( bool withLeaves, double theHeight ) :

hasLeaves( withLeaves ), height (theHeight) { }

private:

bool hasLeaves;

double height;

};

What if we want to create a plant with some parametric member variables?

Now we can create another plant ( in main() ):

Plant myOtherPlant( false, 1 );

Now we have 2 constructors:• Default: Plant() no parameters• Another: Plant( bool withLeaves,

double theHeight )

Construction

What if have only non default constructor (or constructors)?

class Plant

{

public:

Plant( bool withLeaves, double theHeight ) :

hasLeaves( withLeaves ), height (theHeight) { }

private:

bool hasLeaves;

double height;

};

Can we now create a plant like that?Plant myPlant;

NO

If we have at least one constructor – the compiler does not create a default one!We have to do it, IF we want to be able to create a default plant:Plant myPlant;

Member functions (methods)

class Plant

{

public:

Plant() : hasLeaves( true ), height( 1 ) { } Plant( bool withLeaves, double theHeight ) :

hasLeaves( withLeaves ), height (theHeight) { }

private:

bool hasLeaves;

double height;

};

Right now we can only create a plant.

But a class is also about behavior!Let’s add our plant some member functions.

Member functions (methods)

class Plant

{

public:

Plant() : hasLeaves( true ), height( 1 ) { } Plant( bool withLeaves, double theHeight ) :

hasLeaves( withLeaves ), height (theHeight) { }

void Grow() { height += 1; }

void Grow( double growBy ) { height += growBy; }

private:

bool hasLeaves;

double height;

};

Now we can not only create – but also Grow a plant:Plant myPlant; // height = 1myPlant.Grow( ); // height = 2myPlant.Grow( 3.5 ); // height =5.5

Separating Interface from Implementation

class Plant

{

public:

Plant();

Plant( bool withLeaves,

double theHeight ) ;

void Grow();

void Grow( double growBy );

private:

bool hasLeaves;

double height;

};

#include “Plant.h”

Plant::Plant() : hasLeaves( true ), height( 1 ) { }

Plant:: Plant( bool withLeaves, double theHeight ) :

hasLeaves( withLeaves ), height (theHeight) { }

void Plant::Grow()

{

height += 1;

}

void Plant::Grow( double growBy )

{

height += growBy;

}

Plant.h Plant.cpp

Is this the best we can do?No – short functions should be inlined!

Default parameters

class Plant

{

public:

Plant( bool withLeaves=true, double theHeight = 1) :

hasLeaves( withLeaves ), height (theHeight) { }

void Grow(double growBy = 1) { height += growBy ; }

private:

bool hasLeaves;

double height;

};

Same functionality:Plant myPlant; // height = 1myPlant.Grow( ); // height = 2myPlant.Grow( 3.5 ); // height = 5.5

But less code!

Can we create a plant like this?

Plant otherPlant(false);

Plant anotherPlant(2.5);

Problem?class Plant

{

public:

Plant( bool withLeaves=true, double theHeight = 1) :

hasLeaves( withLeaves ), height (theHeight) { }

void Grow(double growBy = 1) { height += growBy ; }

private:

bool hasLeaves;

double height;

};

Plant otherPlant(false);

works and creates Plant without leaves and with height=1 - OK

Plant otherPlant(2.5);

works and creates Plant with leaves and with height=1 – Huh???

Problem?

class Plant

{

public:

Plant( bool withLeaves=true, double theHeight = 1) :

hasLeaves( withLeaves ), height (theHeight) { }

void Grow(double growBy = 1) { height += growBy ; }

private:

bool hasLeaves;

double height;

};

Plant otherPlant(2.5);

calls Plant(bool withLeaves)

after converting 2.5 to bool (to a value true)

Not what we wanted!

This definition is equivalent to defining 3 constructors:Plant();Plant(bool withLeaves);Plant(bool withLeaves, double theHeight);

Solution!class Plant{

public: Plant( double theHeight ) :

hasLeaves( true ), height (theHeight) { }Plant( bool withLeaves=true, double theHeight = 1) :

hasLeaves( withLeaves ), height (theHeight) { }void Grow(double growBy = 1) { height += growBy ; }

private:bool hasLeaves;double height;

};

Now Plant otherPlant(2.5);

calls Plant(double theHeight)

as we wanted. But how does it know what we want? And what will

Plant otherPlant(1); do?

We add another constructor, that gets only height as a parameter:

Overload resolution Step 1: Find candidates:

Same name and viable Step 2: Find viable functions:

Same number of arguments.Parameters can be converted to the types

specified at function declaration. Step 3: Select best matching viable function:

Determined by number of conversions needed. Several viable functions with the same number of

conversions needed cause compilation error, due to ambiguity.

Overload resolution -example

void f( int i ) { };

void f( double d = 4.0, int k = 1) { };

(1) f( 5.0 ); // called void f( double d = 4.0, int k = 1)

(2) f( 5 ); // void f( int i )

(3) f( true); // Ambiguity error ! Both viable functions //need one conversion !

Step 1: same function name =>candidates. Step 2: viable functions. Step 3: select best matching viable. Go back to slide 14 – Plant constructor.

Construction – the detailsWhat is the difference between

and

Member variables are created before any class code is executed, using the values in the initialization line of the constructor

If no values are given – the default construction is used: default (parameterless) constructor for classes no initialization (random value) for built-in types

The first option is better – why?

Plant( bool withLeaves = true, double theHeight = 1) : hasLeaves( withLeaves ), height (theHeight) { }

Plant( bool withLeaves = true, double theHeight = 1){ hasLeaves = withLeaves; height = theHeight;}

Construction – the details

better than

It is obvious that fields are being initialized – easier to understand Better performance for members that are classes Legal even if there is no default constructor for the member Legal even if the member cannot be assigned

In particular, the only way to initialize const and reference members

Better suited for (multiple) inheritance (later in the course)

Plant( bool withLeaves=true, double theHeight = 1) : hasLeaves( withLeaves ), height (theHeight) { }

Plant( bool withLeaves=true, double theHeight = 1){ hasLeaves = withLeaves; height = theHeight;}

Array member construction

Suppose we want to define a class that represents a flower clock, and contains an array of plants:

class FlowerClock{public: FlowerClock() {}private:

Plant plants[24]; /* Some members */}; What happens during initialization of FlowerClock? How can we initialize all members to have height 2?

Array member construction

class FlowerClock{public: FlowerClock() {}private:

Plant plants[24]; /* Some members */};

Reminder:1. Member variables are created before any

class code is executed, using the values in the initialization line of the constructor

2. If no values are given – the default construction is used to create the member

3. The default construction for arrays is:• If elements are classes – initialize them

using default (parameterless) constructor• If elements are built-in types - no

initialization (random value)

So what we have is an array of 24 plants, each with values initialized by the default constructor of Plant –with leaves and with height=1

Array member constructionclass FlowerClock{public: FlowerClock() {}private:

Plant plants[24]; /* Some members */};

How can we initialize all plants to have height 2?For a regular array variable, we can write:Plant couple[2] = {Plant(true,2), Plant(false,2)};For a class member that is an array –

there is no way!Array members are always initialized in the default manner – no explicit values allowed!

To put non-default values, we must write code inside the constructor:FlowerClock::FlowerClock(){ for (size_t i=0; i<24; i++) { plants[i] = Plant(true, 2); // Assumes Plant can be assigned! }}