constructor, destructor, accessibility and virtual functions · pdf fileconstructor,...

38
Constructor, Destructor, Accessibility and Virtual Functions 182.132 VL Objektorientierte Programmierung Raimund Kirner Mitwirkung an Folienerstellung: Astrit Ademaj

Upload: lammien

Post on 13-Mar-2018

247 views

Category:

Documents


3 download

TRANSCRIPT

Constructor, Destructor,

Accessibility and Virtual Functions

182.132 VL Objektorientierte Programmierung

Raimund Kirner

Mitwirkung an Folienerstellung: Astrit Ademaj

Agenda

• Constructor

• Destructors

• this pointer

• Inheritance / Accessibility

• Virtual functions

Class

• A class consists of:

– member data (usually private)

– member functions (usually public)

• the simplest class shall have at least two member functions:

– set data

– show data

– member data can be public, and member functions can be private

Member data initialization

• After an object is created:

– Standard ways for data initialization:

• Setting default constants

• Reading input from user (using cin >>)

• ...

Member data initialization - exampleclass circle

{

private:

int xC, yC, radius ;

public:

void set (int x, int y, int r)

{

xC = x; yC = y; radius = r;

}

void get ()

{ cout << “\Enter x coordinate: “ ; cin >> xC;

cout << “\Enter y coordinate: “ ; cin >> yC;

cout << “\Enter radius : “ ; cin >> radius;

}

void draw ()

{

draw_circle(xC, yC, radius);

}

}

int main() {

...

circle c1, c2;

c1.set (15, 17, 8);

c2.get ();

c1.draw();

c2.draw()

...

}

Member data initialization

• during the object instantiation

– use a special member function called

CONSTRUCTOR (ctor)

Constructor

• Constructor is a member function that has the same name

as the class

• To use a constructor it has to be declared public

• Constructor can be used to initialize data members of a

class

• Is called automatically when an object of the class is created

(instantiated)

Constructor - exampleclass circle

{

private:

int xC, yC, radius ;

public:

circle()

{

xC = 25 ; yC = 25 ; radius = 5;

}

void set (int x, int y, int r)

{

xC = x; yC = y; radius = r;

}

void get ()

{ cout << “\Enter x coordinate: “ ; cin >> xC;

cout << “\Enter y coordinate: “ ; cin >> yC;

cout << “\Enter radius : “ ; cin >> radius;

}

void draw ()

{

draw_circle(xC, yC, radius);

}

}

int main() {

...

circle c1, c2;

c1.set (15, 17, 8);

c1.draw();

c2.draw()

...

}

Constructor• Last example shows the constructor - i.e, the constructor

that takes no arguments either due to

– All parameters have default values (showed in the example), or

– No parameters are required

• Constructor does not return a value (void)

– to whom should it !?

int main() {

...

circle c1;

// default ctor will be executed

...

}

int main() {

...

circle c1();

/* declaration of function c1() that has a

circle-object as return value */

...

}

Constructor

• If no constructor is defined, a compiler generates one:

– default constructor

– if you don’t care how data are being initialized

• If user defines a no-argument constructor

– member data are initialized using the no-argument

constructor

Initializer Listclass circle

{

private:

int xC, yC, radius ;

public:

circle() : xC(25), yC(25), radius(5)

{ /* empty body */ }

void set (int x, int y, int r)

{

xC = x; yC = y; radius = r;

}

void get ()

{ cout << “\Enter x coordinate: “ ; cin >> xC;

cout << “\Enter y coordinate: “ ; cin >> yC;

cout << “\Enter radius : “ ; cin >> radius;

}

void draw ()

{

draw_circle(xC, yC, radius);

}

}

• Initialization takes place before the function body

• Members initialized in the initializer list and initialized before the

constructor is executed

• Why not initialize members in constructor body?

• const member data initialization

Constructor with parametersclass circle

{

private:

int xC, yC, radius ;

public:

circle( int x, int y, int r) : xC (x) , yC(y) , radius(r)

{ /* empty body */ }

void set (int x, int y, int r)

{

xC = x; yC = y; radius = r;

}

void get ()

{ cout << “\Enter x coordinate: “ ; cin >> xC;

cout << “\Enter y coordinate: “ ; cin >> yC;

cout << “\Enter radius : “ ; cin >> radius;

}

void draw ()

{

draw_circle(xC, yC, radius);

}

}

int main() {

...

circle c1(15,25,10);

c1.draw();

...

}

Constructor overloading

• A class can have more than 1 constructor

• Overloaded constructors shall have different parameter lists

– circle();

– circle (int x, int y, int r);

Constructor overloadingclass circle

{

private:

int xC, yC, radius ;

public:

circle() : xC(25) , yC(25) , radius(5)

{ }

circle( int x, int y, int r) : xC (x) , yC(y), radius(r)

{ }

void set (int x, int y, int r)

{

xC = x; yC = y; radius = r;

}

void get ()

{ cout << “\Enter x coordinate: “ ; cin >> xC;

cout << “\Enter y coordinate: “ ; cin >> yC;

cout << “\Enter radius : “ ; cin >> radius;

}

void draw ()

{

draw_circle(xC, yC, radius);

}

}

int main() {

...

circle c1(15,25,10);

circle c2;

c1.draw();

c2.draw();

...

}

} overloading

Only one default constructor is allowed

Member function overloading

• Non-constructor member functions can also be overloaded

– set (int x, int y, int r)

– set (int x, int y)

• Must have unique parameter lists (as with constructors)

Member function overloadingclass circle

{

private:

int xC, yC, radius ;

public:

circle() : xC(25), yC(25), radius(5)

{}

void set (int x, int y, int r)

{

xC = x; yC = y; radius = r;

}

void set (int x, int y)

{

xC = x; yC = y

}

void draw ()

{

draw_circle(xC, yC, radius);

}

}

int main() {

...

circle c1;

c1.set(15,15,10);

c1.draw();

c1.set(20,20);

c1.draw();

...

}

} overloading

Data Initialization• No-argument constructor - initialize with constant

• Constructor with arguments

• Useful feature

– Initialize the data with another object of the same type

Default Copy Constructor• need not to be created (its for free )

• a constructor which takes one object as argument

Copy Constructor class circle

{

private:

int xC, yC, radius ;

public:

circle() : xC(25) , yC(25) , radius(5)

{ }

circle( int x, int y, int r) : xC (x) , yC(y), radius(r)

{ }

void set (int x, int y, int r)

{

xC = x; yC = y; radius = r;

}

void get ()

{ cout << “\Enter x coordinate: “ ; cin >> xC;

cout << “\Enter y coordinate: “ ; cin >> yC;

cout << “\Enter radius : “ ; cin >> radius;

}

void draw ()

{

draw_circle(xC, yC, radius);

}

}

int main() {

...

circle c1(15,25,10);

circle c2(c1);

circle c3 = c1;

c1.draw();

c2.draw();

c3.draw();

...

}

Destructors

• Public member function automatically called when an object is deleted (e.g., when the program finishes)

• Destructor name is ~className, e.g., ~circle

• It has no return type (to whom?) and takes no arguments

• Only 1 destructor is allowed per class

– it cannot be overloaded, as it does not take arguments

Destructorsclass circle

{ private:

int xC, yC, radius, ID *nColour;

public:

~circle ()

{

delete nColour;

cout << “Deleting circle with ID: “<< ID << “\n” ;

}

void set (int x, int y, int r, int circleColour)

{

xC = x; yC = y; radius = r; *nColour= circleColour

}

circle( int x, int y, int r, int id) : xC (x), yC(y), radius(r), ID(id)

{nColour = new int;}

void draw ()

{

draw_circle(xC, yC, radius, nColour);

}

}

int main() {

...

circle c1(15,25,10,1);

circle c2(15,15,10,2);

...

cout << “--– end ---\n”;

}

--- end ---

Deleting circle with ID: 2

Deleting circle with ID: 1

Copy Constructors

• Take care when a class uses pointers

• Copy constructor initializes the pointers ending up pointing into the same memory (defined by the old class)

• When the old class destroys the memory by using the destructor

– the new class will still have a pointer to that memory.

• Solution:

– create its own copy constructor and allocate the memory as required.

Copy constructorclass circle

{ private:

int xC, yC, radius, ID, *nColour;

public:

~circle ()

{ delete nColour;

cout << “Deleting circle with ID: “<< ID << “\n” ;

}

int GetColour() {return * nColour ;}

circle( int x, int y, int r, int id) : xC(x), yC(y), radius(r),ID(id)

{nColour = new int;}

void draw ()

{ draw_circle(xC, yC, radius, nColour);

}

circle (circle & tmpcircle )

{

nColour = new int;

nColour = tmpcircle.GetColour();

}

}

Copy constructor

• Copy constructor required to use reference parameters, and therefore it will have access to their argument’s data

• The purpose is to make a copy of the argument,

– no reason the constructor should modify the argument’s data

• Thus, specify the keyword const in the parameter list

circle (const circle & tmpcircle )

this pointer

• The this pointer points to the class object instance

by the member function.

• Hidden object parameter for each member

function

• All member data and member functions can be

accessed using the this pointer

this pointer

• Can be used to compare a particular object with

the member function of the object being executed.

• Can be used to access members that may be hidden by parameters with the same name.

this pointerclass circle

{

private:

int xC, yC, radius ;

public:

circle() : xC(25), yC(25), radius(5)

{ /* empty body */ }

void set (int xC, int yC, int radius)

{

this->xC = xC;

this->yC = yC;

this->radius = radius;

}

void get ()

{ cout << “\Enter x coordinate: “ ; cin >> this-> xC;

cout << “\Enter y coordinate: “ ; cin >> this-> yC;

cout << “\Enter radius : “ ; cin >> radius;

}

void draw ()

{

draw_circle(xC, yC, radius);

}

}

No difference between the

cin >> this-> xC; and

cin >> xC;

Accessibility

• Private - only within the class

• Protected - within the class and the derived class

• Public – open (not protected) and accessible from

everywhere in the program

Inheritanceclass grafobject

{

protected:

int xC, yC;

public:

grafobject() xC(25), yC(25)

{cout << “GRAFOBJECT constructor “;}

void set (int x, int y)

{

xC = x; yC = y;

}

}

class circle : public grafobject

{

private:

int radius ;

public:

circle () radius(5)

{cout << “CIRCLE constructor “;}

...

}

class cannot invoke private members from

base class

Inheritance don’t work in reverse. Base class

do not know about the members from the

classes that are derived from the base class.

} base class

} derived class

Inheritance: Constructor and Destructorsclass grafobject

{ protected:

int xC, yC, ncolour;

public:

grafobject():xC(25), yC(25) {cout << “GRAFOBJECT constructor “;}

~grafobject() {cout << “GRAFOBJECT destructor “;}

void set (int x, int y)

void linecolour (int ncolour)

{ ...

cout << “Set GRAFOBJECT colour “;}

...

}

class circle : public grafobject

{ private:

int radius ;

public:

circle (): radius(5)

{cout << “CIRCLE constructor “;}

~circle () {cout << “CIRCLE destructor “;}

void draw() {...}

void linecolour (int ncolour)

{ cout << “Set Circle colour “;}

...

}

int main() {

circle c1 ;

c1.draw();

cout << “--– end ---\n”;

}

GRAFOBJECT constructor

CIRCLE constructor

--- end ---

CIRCLE destructor

GRAFOBJECT destructor

Derived class constructor class grafobject

{

protected:

int xC, yC;

public:

grafobject() : xC(15), yC(15) { }

grafobject(int x, int y) : xC(x), yC(y) { }

...

}

class circle : public grafobject

{

privat:

int radius;

public:

circle() : grafobject()

{radius = 0;}

circle (int x, int y, int r) : grafobject(x,y)

{radius = r;}

}

Overloaded constructors in the base class

impose overloaded constructors in the

derived class

Calling constructor from the initialization list.

Calling the base method from overridden methodclass grafobject

{ protected:

int xC, yC, ncolour;

public:

grafobject():xC(25), yC(25) {cout << “GRAFOBJECT constructor “;}

~grafobject() {cout << “GRAFOBJECT destructor “;}

void set (int x, int y)

void setlinecolour (int ncolour)

{ ...

cout << “Set GRAFOBJECT colour “;}

...

}

class circle : public grafobject

{ private:

int radius ;

public:

circle (): radius(5)

{cout << “CIRCLE constructor “;}

~circle () {cout << “CIRCLE destructor “;}

void draw() {...}

void setlinecolour (int ncolour)

{...

cout << “Set Circle colour “;}

}

int main() {

circle c1;

c1.setlinecolour(255);

c1.draw();

c1.grafobject::setlinecolour(125);

cout << “--- end ---\n”;

}

Override (overwrite): crate a method in a derived class

that has the same name and the same signature as the

method in the base class.

Pointers to member functionclass Base

{

public:

void show()

{ cout << “Show Base class “;}

}

class Derived1 : public Base

{ public:

void show()

{ cout << “Show Derived 1 class “;}

}

class Derived2 : public Base

{ public:

void show()

{ cout << “Show Derived 2 class “;}

}

int main() {

Derived1 d1;

Derived2 d2;

Base *pobj

pobj = & d1;

*pobj->show();

pobj = & d2;

*pobj->show();

}

Show Base class

Show Base class

Compiler does not complain because the member

functions are type-compatible and selects the function

that matches the type.

Virtual Functions

• Used to override member functions

• Calling a function in one class may call a function in

another class

• Enables an execution of different functions by using

the same function name - POLIMORPHYSMUS

Virtual Functionsclass Base

{

public:

virtual void show()

{ cout << “Show Base class “;}

}

class Derived1 : public Base

{ public:

void show()

{ cout << “Show Derived 1 class “;}

}

class Derived2 : public Base

{ public:

void show()

{ cout << “Show Derived 2 class “;}

}

int main() {

Derived1 d1;

Derived2 d2;

Base *pobj

pobj = & d1;

*pobj->show();

pobj = & d2;

*pobj->show();

}

Show Derived 1 class

Show Derived 2 class

Compiler selects the function that matches the content

(and not only the type)

Virtual Destructors

• Usually destructors are used to free memory (delete)

• If destructor is not declared virtual - only the memory of the

base class is destroyed

• Base class destructors should be virtual

– The destructors of the derived class are called

Non-Virtual Destructorsclass Base

{

public:

virtual void show() { cout << “Show Base class “;}

~Base () { cout << “Base destroyed “;}

}

class Derived1 : public Base

{ public:

void show(){ cout << “Show Derived 1 class “;}

~ Derived1 () { cout << “Derived 1 destroyed “;}

}int main() {

Base *pBase = new Derived

delete pBase ;

return 0;

}

Base destroyed

Virtual Destructorsclass Base

{

public:

virtual void show() { cout << “Show Base class “;}

virtual ~Base () { cout << “Base destroyed “;}

}

class Derived1 : public Base

{ public:

void show(){ cout << “Show Derived 1 class “;}

~ Derived1 () { cout << “Derived 1 destroyed “;}

}

int main() {

Base *pBase = new Derived

delete pBase ;

return 0;

}

Derived 1 destroyed

Base destroyed

Literature for further reading:

• Object-oriented programming in C++

– Robert Lafore

• Teach yourself C++ in 21 Days

– Jasse Liberty

• C++ Master Class

– Andre Willms