Lecture
No.15 OOP cs 304
   

   
Composition:
  We saw composition in last lecture, its
Conceptual notation is given below,

We
created student object in main as by passing name, rollno and gpa and then displayed
the name of student using GetNamePtr member function of student class,

int
main(){
  Student aStudent("Fakhir",
899,3.1);
  cout << endl;
  cout << “Name:” <<
aStudent.GetNamePtr()<< endl;
  return 0;
  }


 Output:
The
output of our code is given below,

Constructor::String..
Constructor::Student..
Name:  Fakhir
Destructor::Student..
Destructor::String..

 Constructor Code:
Let us see the constructor code again,

      Student::Student(char * n, int roll, float
g){
            cout
<<"Constructor::Student..\n";
            name.SetString(n);
            rollNumber = roll;
            gpa = g;
           }






In
this code we are setting string data member name of Student class using SetString
but the problem in this approach is that we have to call SetString method
explicitly to set value in string class, the reason for it is that our String
class doesn’t support setting its value while creating its object this is the
reason we have to use the function SetString in the constructor.
This
is an overhead and also not very good way to set any object value, we want to
initialize our string sub-object name in the student class as we
initialize other objects using constructor. For achieving this functionality we
add an overloaded constructor in the String class that takes char string
as parameter and initialize the String class object with this value using the
Student constructor’s “Member initialization list” as shown below in
bold text:

class
String{
            char *ptr;
public:
            String();
            String(char *);  // constructor with char * as parameter
            String(const String &);
            void SetName(char *);
            ~String();
           
};


 String::String(char * str){
  if(str != NULL){
                        ptr = new
char[strlen(str)+1];
                        strcpy(ptr,
str);
 }

else
ptr = NULL;
     cout << "Overloaded
Constructor::String..\n";

}


Now
Student class constructor code is modified as follows:

class
Student{
private:
            float gpa;
            int rollNumber;
            String name;
public:
           
            Student(char *=NULL, int=0,
float=0.0);
};

  Student::Student(char * n,int roll, float
g):  name(n)  {

            cout <<
"Constructor::Student..\n";
            rollNumber = roll;
            gpa = g;

  }

int
main(){
            Student aStudent("Fakhir",
899, 3.1);
            cout << endl;
            cout << “Name:” <<
aStudent.GetNamePtr()         <<
endl;
            return 0;
}

Output:


Overloaded
Constructor::String..
Constructor::Student..

Name:  Fakhir
Destructor::Student..
Destructor::String..




Now
suppose we want to add date object in student class to store student Birth
Date,
the conceptual diagram will be as given below,




Student
class is modified as follows:

class
Student{
private:
           
            Date birthDate;
            String name;
public:
            Student(char *, const Date &,
int, float);
            ~Student();
           
};

Composition

  Student::Student(char * n, const Date &
d,         int roll, flaot g):
name(n),birthDate(d){
            cout <<
"Constructor::Student..\n";
            rollNumber = roll;
            gpa = g;
  }
 
  Student::~Student(){
            cout <<
"Destructor::Student..\n";
  }
int
main(){
            Date _date(31, 12, 1982);
            Student aStudent("Fakhir",  _date,899,3.5);
            return 0;
}

Output:

            Overloaded Constructor::Date..
            Copy Constructor::Date..
            Overloaded Constructor::String..
            Constructor::Student..
            Destructor::Student..
            Destructor::String..
            Destructor::Date..
            Destructor::Date..



In
composition we made separate object of those concepts that we think were worthy
to be implemented as an object within other object to make our code simpler and
to make functionality modular (divided in parts) and understandable like we
made String class in Student class, but in real life most situations are such
that two distinct (different) objects and one object is using services of the
other one like student and teacher, student and librarian, room and chair,
passenger and bus, book and bookshelf, person and computer so on. In this case
we cannot make one object as part of other object because they exist
independently and only provide services to each other like in case of,

Student
and Teacher:

Student or Teacher object cannot be composed of other one yet they are taking
services of each other.
Passenger
and Bus:

Passenger and Bus are taking services of each other but exist standalone also,
bus includes passengers but passenger are not Part of Bus they can exist
independently as well.

Composition
vs. Aggregation

Aggregation
is a weak relationship than composition because in this relationship two
classes get services of each other but can exist independently as well, main
difference is memory organization of two objects as shown below,






Example:

Take
the example of Room and Chair as given below,



Aggregation
c++ implementation:

In
aggregation, a pointer or reference to an object is created inside a class. The
sub-object has a life that is NOT dependant on the life of its master
class.
e.g

·        
Chairs
can be moved inside or outside at anytime
·        
When
Room is destroyed, the chairs may or may not be destroyed

Aggregation:

class
Room{
private:
            float area;
            Chair * chairs[50];
Public:
            Room();
            void AddChair(Chair *, int chairNo);
            Chair * GetChair(int chairNo);
            bool FoldChair(int chairNo);
           
};

Room::Room(){
for(int
i = 0; i < 50; i++)
chairs[i]
= NULL;
}
void
Room::AddChair(Chair * chair1, int chairNo){
            if(chairNo >= 0 &&
chairNo < 50)
                        chairs[chairNo] =
chair1;
}

Chair
* Room::GetChair(int chairNo){
            if(chairNo >= 0 &&
chairNo < 50)
                        return chairs[chairNo];
            else
                        return NULL;
}

bool
Room::FoldChair(int chairNo){
 if(chairNo >= 0 && chairNo < 50)
            return
chairs[chairNo]->FoldChair();
 else
            return false;
}
int
main(){
   Chair ch1;
   {
      Room r1;
               
r1.AddChair(&ch1, 1);
               
r1.FoldChair(1);
   }
    ch1.UnFoldChair(1);
   return 0;
}


The
functions which are not member functions of the class yet they can access all
private members of the class are called friend functions.

Why
they are needed

They
are needed in situations where we have written code for some function in one
class and it need to be used by other classes as well for example,
Suppose
we wrote the code to compute a complex mathematical formulae in one class but
later it was required by other classes as well, in that case we will make that
function friend of all other classes.

Are
friend functions against the concept of Object Oriented Programming?

It
can be said that friend functions are against the principle of object oriented
programming because they violate the principle of encapsulation which clearly
says that each object methods and functions should be encapsulated in it. But
there we are making our private member accessible to other outside functions.


Consider
the following class:
class
X{
private:
            int a, b;
public:
            void MemberFunction();
           
}

Suppose
we have a global function DoSomething that need to access the private
members of class X, when we will try to access them compiler will generate error
as outside world can not access private members of a class except its member
functions.

void
DoSomething(X obj){

                        obj.a = 3; //Error
                        obj.b = 4; //Error
            }

Friend
Functions

In
order to access the member variables of the class, we must make function friend
of that class,

            class X{
            private:
              
int a, b;
            public:
                       
               
friend void DoSomething(X obj);
            }

Now
the function DoSomething can access data members of class X

void
DoSomething(X obj){

                        obj.a = 3;                   
obj.b
= 4;
            }

Friend
Functions

Prototypes
of friend functions appear in the class definition.
But
friend functions are NOT member functions.

Friend
Functions

Friend
functions can be placed anywhere in the class without any effect
Access
specifiers don’t affect friend functions or classes

            class X{
                        ...
            private:
                        friend void
DoSomething(X);
            public:
                        friend void
DoAnything(X);
                         ...
            };

Friend
Functions

While
the definition of the friend function is:

void
DoSomething(X obj){

            obj.a = 3;                    // No Error
            obj.b = 4;                    // No Error
           
}

friend keyword is not
given in definition.

Friend
Functions

If
keyword friend is used in the function definition, it’s a syntax error

//Error…

friend
void DoSomething(X obj){
           
}

Friend
Classes

Similarly,
one class can also be made friend of another class:
class
X{
            friend class Y;
           
};

Member
functions of class Y can access private data members of class X

class
X{
            friend class Y;
            private:
                        int x_var1, x_var2;
              ...
            };
class Y{
            private:
                        int
y_var1, y_var2;
                        X
objX;
            public:
                        void
setX(){
                                    objX.x_var1 = 1;
                        }
            };
int main(){
                        Y
objY;
                        objY.setX();
                        return 0;
            }

Post a Comment

Don't Forget To Join My FB Group VU Vicky
THANK YOU :)

Previous Post Next Post