OOPc using C++

With this blog I want to share my knowledge of OOPs and C++. I Hope this can quench your thirst for learning.Any suggestions and comments are welcome.

Classes and Objects

Classes


In C++, a class is declared using the class keyword. The syntax of a class declaration is similar to that of a structure. Its general form is,


class class-name 
{
    private: 
           // private functions and variables
   public:
         // public functions and variables
} object-list;


In a class declaration the object-list is optional.The class-name is technically optional. From a practical point of view it is virtually always needed. The reason is that the class-name becomes a new type name that is used to declare objects of the class.Functions and variables declared inside the class declaration are said to be members of the class.

By default, all member functions and variables are private to that class. This means that they are accessible by other members of that class.To declare public class members, the public keyword is used, followed by a colon. All functions and variables declared after the public specifier are accessible both by other members of the class and by any part of the program that contains the class.


#include < iostream >
using namespace std;


// class declaration
class myclass 
{
              // private members to myclass
        int a;
        public:
            // public members to myclass
       void set_a(int num);
       int get_a( );
};


This class has one private variable, called a, and two public functions set_a( ) and get_a( ). Notice that the functions are declared within a class using their prototype forms. The functions that are declared to be part of a class are called member functions.

Since a is private it is not accessible by any code outside myclass. However since set_a( ) and get_a( ) are member of myclass, they have access to a and as they are declared as public member of myclass, they can be called by any part of the program that contains myclass.
The member functions need to be defined. You do this by preceding the function name with the class name followed by two colons (:: are called scope resolution operator). 
For example, outside the class declaration, you can declare the member function as


// member functions declaration outside the class
void myclass::set_a(int num) 
{
       a=num;
}
int myclass::get_a( ) 
{
      return a;
}
In general to declare a member function, you use this form:


return-type class-name::func-name(parameter- list)
{
             // body of function
}


Here the class-name is the name of the class to which the function belongs.
The declaration of a class does not define any objects of the type myclass. It only defines the type of object that will be created when one is actually declared. To create an object, use the class name as type specifier. For example,


// from previous examples
void main( ) 
{
           myclass ob1, ob2;    //these are object of type myclass
                     // ... program code
}
Remember that an object declaration creates a physical entity of that type. That is, an object occupies memory space, but a type definition does not.
Once an object of a class has been created, your program can reference its public members by using the dot operator in much the same way that structure members are accessed. Assuming the preceding object declaration, here some examples,


ob1.set_a(10); // set ob1’s version of a to 10
ob2.set_a(99); // set ob2’s version of a to 99
cout << ob1.get_a( ); << "\n";
cout << ob2.get_a( ); << "\n";
ob1.a=20; // error cannot access private member
ob2.a=80; // by non-member functions.
...
There can be public variables, for example
#include < iostream >
using namespace std;
// class declaration
class myclass 
{
  public:
         int a; //a is now public
                  // and there is no need for set_a( ), get_a( )
};


int main( ) 
{
       myclass ob1, ob2;
       // here a is accessed directly
       ob1.a = 10;
       ob2.a = 99;
       cout << ob1.a << "\n";
       cout << ob1.a << "\n";
return 0;
}


It is important to remember that although all objects of a class share their functions, each object creates and maintains its own data.

Constructors and Destructor

Constructors
When applied to real problems, virtually every object you create will require some sort of initialisation. C++ allows a constructor function to be included in a class declaration. A class’s constructor is called each time an object of that class is created. Thus, any initialization to be performed on an object can be done automatically by the constructor function.
A constructor function has the same name as the class of which it is a part a part and has not return type. Here is a short example,


#include < iostream >
using namespace std;
// class declaration
class myclass 
{
                int a;
     public:

                myclass( ); //constructor
                void show( );
};

myclass::myclass( ) 
{
cout << "In constructor\n";
a=10;
}

myclass::show( ) 
{
     cout << a;
}

int main( ) 
{
       int ob; // automatic call to constructor
      ob.show( );
      return 0;
}










In this simple example the constructor is called when the object is created, and the constructor initialises the private variable a to 10.For a global object, its constructor is called once, when the program first begins execution.For local objects, the constructor is called each time the declaration statement is executed.

Destructors
The complement of a constructor is the destructor. This function is called when an object is destroyed. For example, an object that allocates memory when it is created will want to free that memory when it is destroyed.
The name of a destructor is the name of its class preceded by a ∼. For example,


myclass::∼myclass( )
{
    cout << "Destructing...\n";
} // ...


Click here for the complete program

A class’s destructor is called when an object is destroyed.Local objects are destroyed when they go out of scope. Global objects are destroyed when the program ends.It is not possible to take the address of either a constructor or a destructor.
Note that having a constructor or a destructor perform actions not directly related to initialisation or orderly destruction of an object makes for very poor programming style and should be avoided.

Constructors that take parameters


It is possible to pass one or more arguments to a constructor function. Simply add the appropriate parameters to the constructor function’s declaration and definition. Then, when you declare an object, specify the arguments.


#include < iostream >
using namespace std;
// class declaration
class myclass 
{
               int a;
      public:
              myclass(int x); //constructor
              void show( );
};


myclass::myclass(int x) 
{
         cout << "In constructor\n";
         a=x;
}


void myclass::show( ) 
{
        cout << a <<"\n";
}
int main( ) 
{
        myclass ob(4);
        ob.show( );

return 0;
}


Pay particular attention to how ob is declared in main( ). The value 4, specified in the parentheses following ob, is the argument that is passed to myclass( )’s parameter x that is used to initialise a. Actually, the syntax is shorthand for this longer form:


       myclass ob = myclass(4);


Unlike constructor functions, destructors cannot have parameters.Although the previous example has used a constant value, you can pass an object’s constructor any valid expression, including variables.


OBJECT POINTERS
So far, you have been accessing members of an object by using the dot operator. This is the correct method when you are working with an object. However, it is also possible to access a member of an object via a pointer to that object. When a pointer is used, the arrow operator (->) rather than the dot operator is employed.You declare an object pointer just as you declare a pointer to any other type of variable. Specify its class name, and then precede the variable name with an asterisk.To obtain the address of an object, precede the object with the & operator, just as you do when taking the address of any other type of variable.
Just as pointers to other types, an object pointer, when incremented, will point to the next object of its type. Here a simple example,

#include < iostream >
using namespace std;


class myclass 
{
                   int a;
        public:
                  myclass(int x); //constructor
                 int get( );
};


myclass::myclass(int x) 
{
       a=x;
}


int myclass::get( ) 
{
          return a;
}


int main( ) 
{
          myclass ob(120); //create object
          myclass *p; //create pointer to object
          p=&ob; //put address of ob into p
          cout << "value using object: " << ob.get( );
          cout << "\n";
          cout << "value using pointer: " << p->get( );
          return 0;

}


Notice how the declaration


                     myclass *p;


creates a pointer to an object of myclass. It is important to understand that creation of an object pointer does not create an object. It creates just a pointer to one. The address of ob is put into p by using the statement:
                   
                    p=&ob;

Finally, the program shows how the members of an object can be accessed through a pointer.We will come back to object pointer later. For the moment, here are several special features that relate to them.
More About Classes






Assigning object





One object can be assigned to another provided that both are of the same type. By default, when one object is assigned to another, a bitwise copy of all the data members is made. For example, when an object called o1 is assigned to an object called o2 , the contents of all o1’s data are copied into the equivalent members of o2.

//an example of object assignment.
//...
class myclass
{
        int a, b;
        public:
        void set(int i, int j) { a = i; b = j; };
        void show( ) { cout << a << " " << b << "\n"; }
};

int main( ) 
{


        myclass o1, o2;
        o1.set(10, 4);
       //assign o1 to o2
       o2 = o1;

      o1.show( );
      o2.show( );
      return 0;
}

Thus, when run this program displays
10 4
10 4

Remember that assignment between two objects simply makes the data, in those objects, identical. The two objects are still completely separate.



Only object of the same type can by assign. Further it is not sufficient that the types just be physically similar - their type names must be the same:



// This program has an error

class myclass 
{
                   int a, b;
    public:
                 void set(int i, int j) { a = i; b = j; };
                 void show( ) { cout << a << " " << b << "\n"; }
};

/* This class is similar to myclass but uses a different
type name and thus appears as a different type to
the compiler
*/

class yourclass 
{
          int a, b;
     public:
          void set(int i, int j) { a = i; b = j; };
          void show( ) { cout << a << " " << b << "\n"; }
};

int main( )
 {
        myclass o1;
       yourclass o2;
       o1.set(10, 4);
       o2 = o1;                        //ERROR objects not of same type

       o1.show( );
      o2.show( );
return 0;
}

It is important to understand that all data members of one object are assigned to another when assignment is performed. This included compound data such 







as arrays. But be careful not to destroy any information that may be needed later.











Passing object to functions







Objects can be passed to functions as arguments in just the same way that other types of data are passed. Simply declare the function’s parameter as a class type and then use an object of that class as an argument when calling the function. As with other types of data, by default all objects are passed by value to a function.





// ...





class samp
 {
                int i;
          public:
               samp(int n) { i = n; }
               int get_i( ) { return i; }
};

// Return square of o.i
int sqr_it(samp o) 
{
         return o.get_i( )* o.get_i( );
}

int main( ) 
{
          samp a(10), b(2);
          cout << sqr_it(a) << "\n";
          cout << sqr_it(b) << "\n";
return 0;
}

As stated, the default method of parameter passing in C++, including objects, is by value. This means that a bitwise copy of the argument is made and it is this copy that is used by the function. Therefore, changes to the object inside the function do not affect the object in the call.
As with other types of variables the address of an object can be passed to a function so that the argument used in the call can be modify by the function.










// Set o.i to its square.
// This affect the calling argument
void sqr_it(samp *o) 
{
        o->set(o->get_i( )*o->get_i( ));
}
// ...
int main( )
 {
       samp a(10);
       sqr_it(&a); // pass a’s address to sqr_it
// ...
}

Notice that when a copy of an object is created because it is used as an argument to a function, the constructor function is not called. However when the copy is destroyed (usually by going out of scope when the function returns), the destructor function is called.
Be careful, the fact that the destructor for the object that is a copy of the argument is executed when the function terminates can be a source of problems. Particularly, if the object uses as argument allocates dynamic memory and frees that that memory when destroyed, its copy will free the same memory when its destructor is called.
One way around this problem of a parameter’s destructor function destroying data needed by the calling argument is to pass the address of the object and not the object itself. When an address is passed no new object is created and therefore no destructor is called when the function returns.
A better solution is to use a special type of constructor called copy constructor, which we will see later on.

Returning object from functions

Functions can return objects. First, declare the function as returning a class type. Second, return an object of that type using the normal return statement.
Remember that when an object is returned by a function, a temporary object is automatically created which holds the return value. It is this object that is actually returned by the function. After the value is returned, this object is destroyed. The destruction of the temporary object might cause unexpected side effects in some situations (e.g. when freeing dynamically allocated memory).
//Returning an object
// ...
class samp
 {


          char s[80];
     public:
           void show( ) { cout << s << "\n"; }
           void set(char *str) { strcpy(s, str); }
};

//Return an object of type samp
samp input( ) 
{
        char s[80];
        samp str;
        cout << "Enter a string: ";
        cin >> s;
        str.set(s);

return str;
}

int main( ) 
{
      samp ob;
               //assign returned object to ob
      ob = input( );
      ob.show( );

return 0;
}



Friend functions: an introduction

There will be time when you want a function to have access to the private members of a class without that function actually being a member of that class. Towards this, C++ supports friend functions. A friend function is not a member of a class but still has access to its private elements.
Friend functions are useful with operator overloading and the creation of certain types of I/O functions.
A friend function is defined as a regular, nonmember function. However, inside the class declaration for which it will be a friend, its prototype is also included, prefaced by the keyword friend. To understand how this works, here a short example:

//Example of a friend function
// ...
class myclass
{
            int n, d;
       public:
            myclass(int i, int j)
                 {
                     n = i;





                     d = j;
                  }
//declare a friend of myclass
friend int isfactor(myclass ob);
};


/* Here is friend function definition. It returns true
if d is a factor of n. Notice that the keyword friend
is not used in the definition of isfactor( ).
*/


int isfactor(myclass ob) 
{
            if ( !(ob.n % ob.d) ) return 1;
            else return 0;
}


int main( ) 
{
         myclass ob1(10, 2), ob2(13, 3);
         if (isfactor(ob1)) 
                     cout << "2 is a factor of 10\n";
         else 
                     cout << "2 is not a factor of 10\n";
         if (isfactor(ob2)) 
                     cout << "3 is a factor of 13\n";
         else 
                     cout << "3 is not a factor of 13\n";
return 0;
}


It is important to understand that a friend function is not a member of the class for which it is a friend. Thus, it is not possible to call a friend function by using an object name and a class member access operator (dot or arrow). For example, what follows is wrong.

ob1.isfactor( );            //wrong isfactor is not a member function


Instead friend functions are called just like regular functions.Because friends are not members of a class, they will typically be passed one or more objects of the class for which they are friends. This is the case with isfactor( ). It is passed an object of myclass, called ob. However, because isfactor( ) is a friend of myclass, it can access ob’s private members. If isfactor( ) had not been made a friend of myclass it would not have access to ob.d or ob.n since n and d are private members of myclass.
A friend function is not inherited. That is, when a base class includes a friend function, that friend function is not a friend function of the derived class.
A friend function can be friends with more than one class. For example,
// ...


class truck; //This is a forward declaration
class car 
{
              int passengers;
              int speed;
   public:
        car(int p, int s) { passengers = p; speed =s; }
        friend int sp_greater(car c, truck t);
};


class truck 
{
            int weight;
            int speed;
    public:
           truck(int w, int s) { weight = w; speed = s; }
           friend int sp_greater(car c, truck t);
};


int sp_greater(car c, truck t) 
{
      return c.speed - t.speed;
}
int main( ) 
{
// ...
}


This program also illustrates one important element: the forward declaration (also called a forward reference), to tell the compiler that an identifier is the name of a class without actually declaring it.
A function can be a member of one class and a friend of another class. For example,
// ...
class truck; // forward declaration
class car
 {
       int passengers;
       int speed;
  public:
         car(int p, int s) { passengers = p; speed =s; }
         int sp_greater( truck t);
};


class truck 
{
      int weight;
      int speed;

  public:
      truck(int w, int s) { weight = w; speed = s; }
      //note new use of the scope resolution operator
      friend int car::sp_greater( truck t);
};

int car::sp_greater(truck t) 
{
     return speed - t.speed;
}
int main( ) 
{
    // ...
}
One easy way to remember how to use the scope resolution operation it is never wrong to fully specify its name as above in class truck,


friend int car::sp_greater( truck t);


However, when an object is used to call a member function or access a member variable, the full name is redundant and seldom used. For example,
// ...
int main( ) {
int t;
car c1(6, 55);
truck t1(10000, 55);
t = c1.sp_greater(t1); //can be written using the
//redundant scope as
t = c1.car::sp_greater(t1);
//...
}

However, since c1 is an object of type car the compiler already knows that sp_greater( ) is a member of the car class, making the full class specification unnecessary.