constructor, destructor, accessibility and virtual functions · pdf fileconstructor,...
TRANSCRIPT
Constructor, Destructor,
Accessibility and Virtual Functions
182.132 VL Objektorientierte Programmierung
Raimund Kirner
Mitwirkung an Folienerstellung: Astrit Ademaj
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