Object Oriented Programming in C++ Chapter 4: More Class Features
CHAPTER FOUR
MORE CLASS FEATURES
Objects Academy, 2014 Page 4-1
MORE CLASS FEATURES
In Chapters 2 and 3, you learned how to write a class definition, encapsulate member data and functions, specify access categories, create instances of the class and write constructor and destructor functions. However, there are many more features of C++ classes with which you must be familiar before moving to such topics as inheritance, function overloading, and polymorphism.
THE this POINTER
? When several instances of a class come into existence, it naturally follows that each instance has its own copy of the separate member variables.
? Only one copy of each member function per class is stored in memory, and must therefore be shared by all the instances of the class.
? How can any given member function of a class know which instance it is supposed to be working on?
? The compiler passes, behind the scene, to each member function a pointer variable that points to the object being manipulated.
? This pointer variable has the special name this, which is a keyword.
? In the case of constructor and destructor, the this pointer points to the instance being created and destroyed.
? The this pointer is supplied to each member function automatically when the function is called.
? You always have access to the this pointer and may use it anywhere you deem necessary within the scope of the member function being worked on.
//this1.cpp
#include iostream.h
#include string.h
#include stdlib.h
#include assert.h
class Student
{ char* name; long ssn;
public:
Student (char*, long);
Student (const Student& );
~Student(); char * getName ( );
long getSsn ( );
} ;
Student::Student (char* nm, long l_ssn)
{
cout -constructor- endl; ssn = l_ssn;
name = new char[strlen(nm) +1]; assert(name);
strcpy (name, nm);
}
Student::Student (const Student& s)
{
cout -copy constructor- endl; ssn = s.ssn;
name = new char[strlen(s.name) +1]; assert(name); strcpy (name, s.name);
}
Student::~Student ()
{
cout -destructor- endl;
delete [] name;
}
long Student::getSsn ( )
{
return ssn ;
}
char * Student::getName ( )
{
return name ;
}
int main ()
{ // Instantiate st1
Student st1(-John K. Smith-, 502817792L);
// Retrieve the names and ssn for st1 and print them cout -Name:- st1.getName() endl; cout -SSN:- st1.getSsn () endl;
// Instantiate st2 from st1
Student st2(st1);
// Retrieve the names and ssn for st2 and print them cout -Name:- st2.getName() endl; cout -SSN:- st2.getSsn () endl;
} // end of main
The output is:
constructor Name:John K. Smith SSN: 502817792
copy constructor Name:John K. Smith SSN: 502817792
destructor destructor
Example 4.1:
? Now let’s rewrite the same program using the this pointer explicitly.
//this2.cpp
#include iostream.h
#include string.h
#include stdlib.h
#include assert.h
class Student
{ char* name; long ssn;
public:
Student (char*, long);
Student (const Student& );
~Student(); char * getName ( );
long getSsn ( );
} ;
Student::Student (char* nm, long l_ssn)
{
cout -constructor- endl; this- ssn = l_ssn;
this- name = new char[strlen(nm) +1]; assert(this- name);
strcpy (this- name, nm);
}
Student::Student (const Student& s)
{
cout -copy constructor- endl; this- ssn = s.ssn;
this- name = new char[strlen(s.name) +1]; assert(this- name); strcpy (this- name, s.name);
}
Student::~Student ()
{
cout -destructor- endl;
delete [] name;
}
long Student::getSsn ( )
{
return this- ssn ;
}
char * Student::getName ( )
{
return this- name ;
}
int main ()
{
// Instantiate st1
Student st1(-John K. Smith-, 512867592L);
// Retrieve the names and ssn for st1 and print them cout -Name:- st1.getName() endl; cout -SSN:- st1.getSsn () endl;
// Instantiate st2 from st1
Student st2(st1);
// Retrieve the names and ssn for st2 and print them cout -Name:- st2.getName() endl; cout -SSN:- st2.getSsn () endl;
} // end of main
The output is:
constructor Name:John K. Smith SSN: 502817792
copy constructor
Name:John K. Smith SSN: 502817792
destructor destructor
Example 4.2:
EXERCISE # 9
Modify exercise # 8, the latest version of the complex class, by adding the this pointer explicitly to obtain the same output.
FRIEND FUNCTIONS
? It is possible to allow a non-member function to access the private members of a class. It is achieved by declaring a non-member function as a friend of a class.
? Friend functions should be used in exceptional cases, otherwise declaring too many functions as friend will compromise the integrity of the class.
class Student
{
.... public:
....
// friend function declaration friend void f1( const Student * ptr );
} ;
void f1 (Student * ptr )
{
// function code
}
Example 4.3:
? friend functions can be declared anywhere in a class, and their position is not affected by private, public or protected specifies.
? There are three situations in which a class grant friendship:
1. To a non-member function
2. To another class (implying that all the member functions of that class are friend functions)
3. To a particular member function of another class.
? The following example illustrates the use of a friend function to print the value of the private data members of the class Student.
//friend1.cpp
#include iostream.h
#include string.h
#include stdlib.h
#include assert.h
class Student
{
char* name; long ssn;
public:
Student (char*, long);
Student (const Student& );
~Student();
// Declaration of a friend function
void friend print (const Student &);
} ;
Student::Student (char* nm, long l_ssn)
{
cout -constructor- endl; ssn = l_ssn;
name = new char[strlen(nm) +1];
assert(name);
strcpy (name, nm);
}
Student::Student (const Student& s)
{
cout -copy constructor- endl; ssn = s.ssn;
name = new char[strlen(s.name) +1];
assert(name); strcpy (name, s.name);
}
Student::~Student ()
{
cout -destructor- endl;
delete [] name;
}
void print (const Student& s)
{
cout -Name:- s.name endl;
cout -SSN:- s.ssn endl;
}
int main ()
{
Student st1(-John K. Smith-, 502817792L);
//Retrieve the names and ssn for st1 and print them using a friend function
print(st1);
Student st2(st1);
print(st2);
}
The output is:
constructor Name:John K. Smith SSN: 502817792
copy constructor Name:John K. Smith SSN: 502817792
destructor destructor
Example 4.4:
GRANTING FRIENDSHIP TO ANOTHER CLASS
? To make all the functions of class B friends of class A, include the following statement friend B in the declaration of A:
Class B; //
Class A
{
..... public:
.....
friend B;
};
Class B
{
..... public:
void f1( A & obj); void f2(A& obj); void f3(A& obj);
}; forward declaration
Example 4.5:
//friend2.cpp
#include iostream.h
#include string.h
#include stdlib.h
#include assert.h
class Professor; // forward declaration
class Student
{
char* name; long ssn;
public:
Student (char*, long);
~Student();
// Declaration of a friend class friend Professor;
} ;
class Professor
{
char* Pname; long Pssn; int pub;
public:
Professor (char*, long, int);
Professor(); long getSsn ( ); char * getName (); int getPub ( );
void print(const Student & );
};
Student::Student (char* nm, long l_ssn)
{
cout -Student constructor- endl; ssn = l_ssn;
name = new char[strlen(nm) +1]; assert(name);
strcpy (name, nm);
}
Student::~Student ()
{
cout -Student destructor- endl; delete [] name;
}
Professor::Professor (char* nm, long l_ssn, int pb)
{
cout -Professor constructor- endl;
Pssn = l_ssn;
pub = pb;
Pname = new char[strlen(nm) +1]; assert(Pname);
strcpy (Pname, nm);
}
Professor::~Professor ()
{
cout -Professor destructor- endl; delete [] Pname;
}
long Professor::getSsn ( )
{
return Pssn ;
}
char * Professor::getName ( )
{
return Pname ;
}
int Professor::getPub ( )
{
return pub ;
}
void Professor::print(const Student & s)
{
cout -Name:- s.name endl;
cout -SSN:- s.ssn endl;
}
int main ()
{
Student st1(-John K. Smith-, 512867592L);
Professor pf1( -Edwin L. Jhonson-, 444444444L, 14);
// retrieve the names, ssn and No. of publications for pf1 and print them cout -Name:- pf1.getName() endl; cout -SSN:- pf1.getSsn () endl;
cout -No. of Publication:- pf1.getPub () endl endl;
//Retrive the names and ssn for st1 and print them using a friend function pf1.print(st1);
return 0;
}
The output is:
Student constructor
Professor constructor
Name:Edwin L. Jhonson
SSN:444444444
No. of Publication:14
Name:John K. Smith
SSN: 502817792
Professor destructor
Student destructor
Example 4.6:
GRANTING FRIENDSHIP TO A MEMBER FUNCTION OF ANOTHER
CLASS
? It is also possible for an individual member function of class Professor to be a friend of class Student.
//friend3.cpp
#include iostream.h
#include string.h
#include stdlib.h
#include assert.h
class Student; // forward declaration
class Professor
{
char* Pname; long Pssn; int pub;
public:
Professor (char*, long, int);
~Professor(); long getSsn ( ); char * getName (); int getPub ( );
void print(const Student & );
};
class Student
{
char* name; long ssn;
public:
Student (char*, long);
~Student();
// Declaration of a friend function friend void Professor::print(const Student & );
} ;
....
.....
int main ()
{
Student st1(-John K. Smith-, 512867592L);
Professor pf1( -Edwin L. Johnson-, 444444444L, 14);
cout -Name:- pf1.getName() endl; cout -SSN:- pf1.getSsn () endl;
cout -No. of Publication:- pf1.getPub () endl endl;
pf1.print(st1);
}
Example 4.7:
? A specific member function Professor::print ( ) may not be a friend of class Student unless the class is already defined. Thus the need for the initial class Student declaration.
TWO CLASSES HAVING THE SAME FRIEND FUNCTION
? It is also possible for a function to be friend to both classes Professor and Student.
//friend4.cpp
#include iostream.h
#include string.h
#include stdlib.h
#include assert.h
class Student;
class Professor
{
... public:
....
friend void print(const Student &,const Professor & );
};
class Student
{
...
public:
...
friend void print(const Student &,const Professor & );
} ;
void print(const Student & s,const Professor & p)
{
cout -Name:- p.Pname endl; cout -SSN:- p.Pssn endl;
cout -No. of Publication:- p.pub endl endl;
cout -Name:- s.name endl;
cout -SSN:- s.ssn endl;
}
int main ()
{
Student st1(-John K. Smith-, 502817792L);
Professor pf1( -Edwin L. Johnson-, 444444444L, 14);
//Retrieve the names, ssns and No. of publications using a friend function print(st1,pf1);
}
Example 4.8:
? Friendship cannot be inherited and there cannot be a friend of a friend.
EXERCISE # 10
Follow up on exercises # 2, the fraction class, by updating main () as shown and by adding the following functions:
? A constructor that accepts two arguments. If the denominator is equal to zero, change it to a 1.
? A copy constructor.
? Change the status of the functions add(), sub(), and mult() from members to friends.
? Modify the function inc() so that it takes no arguments at all. Be sure to enable inc() to facilitates function chaining.
? Make sure to include the const keyword wherever is needed.
int main ( )
{ fraction f1, f2(5L,0L); fraction f3(f2);
f1.print(); f2.print();
f3.print();
f3 = add(f3 , fraction (-7,8) ); f1 = add(f2 , f3);
f1.print ( );
f1 = sub(f2 , f3); f1.print();
f1 = mult( f2, f3); f1.print();
f1.inc ().inc().print();
f1 =div(f2 , f3 ); f1.print();
return 0;
}
The output should be similar to the following:
0/1
5/1
5/1
73/8
7/8
165/8
181/8
40/33
inline FUNCTIONS
? An inline function is a function whose code gets substituted instead of the actual call to that function.
? Inline functions are similar to parameterized macros in C, but provide more flexibility. That is, whenever the compiler encounter a call to an inline function, it merely replaces it with the code itself, thereby saving the function’s call overhead.
inline void f1( int a) {
....
}
Example 4.9:
? Inline functions work best when they are small. The more times they are called, the more savings will be realized.
? An Inline function can be either
1. member of a class
2. A global function
//inline1.cpp
#include iostream.h
#include string.h
#include stdlib.h
#include assert.h
class Student;
class Professor
{
char* Pname; long Pssn; int pub;
public:
Professor (char*, long, int);
~Professor(); long getSsn ( ); char * getName (); int getPub ( );
friend void print(const Student &,const Professor & );
};
class Student
{
char* name; long ssn;
public:
Student (char*, long);
~Student();
// Declaration of a friend class
friend void print(const Student &,const Professor & );
} ;
inline Student::Student (char* nm, long l_ssn)
{
cout -Student constructor- endl; ssn = l_ssn;
name = new char[strlen(nm) +1]; assert(name);
strcpy (name, nm);
}
inline Student::~Student ()
{
cout -Student destructor- endl; delete [ ] name;
}
inline Professor::Professor (char* nm, long l_ssn, int pb)
{
cout -Professor constructor- endl;
Pssn = l_ssn;
pub = pb;
Pname = new char[strlen(nm) +1]; assert(Pname);
strcpy (Pname, nm);
}
inline Professor::~Professor ()
{
cout -Professor destructor- endl; delete [] Pname;
}
//Global inline function inline void print(const Student & s,const Professor & p)
{
cout -Name:- p.Pname endl; cout -SSN:- p.Pssn endl;
cout -No. of Publication:- p.pub endl endl;
cout -Name:- s.name endl;
cout -SSN:- s.ssn endl;
}
int main ()
{
Student st1(-John K. Smith-, 502817792L);
Professor pf1( -Edwin L. Johnson-, 444444444L, 14);
//Retrieve the names, ssns and No. of publications using a friend function print(st1,pf1);
return 0;
}
Example 4.10:
? Two ways to create inline functions
1. use the modifier inline
2. define the body of the function inside the class
//inline2.cpp
#include iostream.h
#include string.h
#include stdlib.h
#include assert.h
class Student;
class Professor
{
char* Pname; long Pssn; int pub;
public:
Professor (char* nm, long l_ssn, int pb)
{
cout -Professor constructor- endl;
Pssn = l_ssn;
pub = pb;
Pname = new char[strlen(nm) +1]; assert(Pname);
strcpy (Pname, nm);
}
~Professor ( )
{
cout -Professor destructor- endl; delete [ ] Pname;
}
friend void print(const Student &,const Professor & );
}; // end of Professor class
class Student
{ char* name; long ssn;
public:
Student (char* nm, long l_ssn)
{
cout -Student constructor- endl;
ssn = l_ssn;
name = new char[strlen(nm) +1];
assert(name);
strcpy (name, nm);
}
~Student () {
cout -Student destructor- endl; delete [ ] name;
}
friend void print(const Student &,const Professor & );
} ; // end of Student class
inline void print(const Student & s,const Professor & p)
{
cout -Name:- p.Pname endl; cout -SSN:- p.Pssn endl;
cout -No. of Publication:- p.pub endl endl; cout -Name:- s.name endl;
cout -SSN:- s.ssn endl;
}
int main ()
{
Student st1(-John K. Smith-, 512867592L);
Professor pf1( -Edwin L. Jhonson-, 444444444L, 14); print(st1,pf1);
}
Example 4.11: ? Inlinning a function is a request, and not a command to the compiler to generate inline code.
? The compiler may or may not honor an inline request depending on the type of code the function contains.
? Any function will not be inlined if it contains any of the following:
1. a loop
2. static data members
3. a switch statement
4. recursive code
EXERCISE # 11
Inline all the functions in exercise # 10 using the two possible methods.
So , you will have two versions of the same exercise.
Version 11-a and version 11-b
GET ANSWERS / LIVE CHAT