Monday 14 October 2013

oops notes - c++ - set 4

1. OVERVIEW OF C++:

What is C++?
C++ is an object-oriented programming language.  Initially named ‘C with classes’, C++ was developed by Bjarne Stroustrup at AT & T Bell Laboratories in Murray Hill, New Jersey, USA, in the early eighties.  Since the class was a major addition to the original C language, Stroustrup called the new language ‘C with classes’, later in 1983 the name was changed to C++.   The idea of C++ comes from the C increment operator ++, thereby suggesting that C++ is an augmented (incremented) version of C.
C++ is a superset of C.  Therefore, almost all C programs are also C++ programs, there are a few minor differences that will prevent a C program to run under C++ compiler.  The three most important facilities that C++ adds on to C are Classes, function overloading, and operator overloading.  These features enable us to create abstract data types, inherit properties from existing data types and support polymorphism, thus making C++ a truly object-oriented language.

Class & Objects
Introducing C++ Classes:
A class may contain private as well as public parts.  By default, all items defined in a class are private.  To make parts of a class public you must declare them after the public keyword.  All variables or functions defined after public can be accessed by all other functions in the program.  In C++ class creates a new data type that may be used to create objects of that type.  An object is an instance of a class in the same way that some other variable is an instance of the int data type.  A class is a logical abstraction while an object is real.
The general form of a simple class declaration is
Class class-name
{
Private:
Variable declarations;
Function declarations;
Public:
Variable declaration;
Function declarations;
};
The class declaration is similar to a struct declaration.  The keyword class specifies that what follows is an abstract data of type class-name. The functions and variables are collectively called members.  They are grouped under two sections, namely, private and public to denote which of the members are private and which of them are public.  The keywords private and public are known as visibility labels.  The members that have been declared as private can be accessed only from within the class.  The public members can be accessed from outside the class also.  The data hiding is the key feature of object-oriented programming.  The use of the keyword private is optional, the members of a class are private.  If both the labels are missing, then by default, all the members are private.
The variables declared inside the class are known as data members and the functions are known as member functions.  Only the member functions can have access to the private data members and private functions.  The public members can be accessed from outside the class.
Object: is a basic runtime entity which may be a person, an item or something like time, date etc.
Ex.
Class item
{
int number;    //variable declaration
float cost;        //private by default
public:
void getdata(int a, float b);   //function declaration
void putdata(void);                //using prototype
}
The class item contains two data members and two function members.  The data members are private by default while both the functions are public by declaration.  The function getdata( ) can be used to assign values to the member variables number and cost, and putdata( ) for displaying their values.

Fuction Overloading:
Overloading refers to the use of the same thing for different purposes.  C++ also permits overloading of function.  This means that we can use the same function name to create functions that perform a variety of different tasks.  This is known as function polymorphism in OOP.  We can design group of functions with one function name but with different argument lists.  The function would perform different operations depending on the argument list in the function call.  The correct function to be invoked is determined by checking the number and type of the arguments but not on the function type.

Ex.
#include<iostream>
using namespace std;
// abs is overloaded three ways
int abs(int i);
double abs(double d);
long abs(long l);
int main( )
{
cout<<abs(-10)<<”\n”;
cout<<abs(-11.0)<<”\n”;
cout<<abs(-9L)<<”\n”;
return 0;
}
int abs(int i)
{
cout<<”using integer abs( )\n”;
return  i<0 ? –i : i;
}
double abs(double d)
{
cout<<”using double abs( )\n”;
return d<0.0 ? –d : d;
}
long abs(long l)
{
cout<< “using long abs( )\n”;
return l<0 ? -1 : 1;
}
output:                                    //10      11        9

Operator Overloading:
The operator overloading is an important technique that has enhanced the power of C++.  C++ tries to make the user-defined data types in much the same way as the built-in type.  C++ permits us to add two variables of user-defined types with the same syntax that is applied to the basic types. This means that C++ has the ability to provide the operators with a special meaning for a data type, this mechanism is known as operator overloading. To define an additional task to an operator, we must specify the class to which the operator is applied. This is done with the help of a special function, called operator function.
The general form of an operator function is
Returntype classname::operator op(arg-list)
{
Function body
}
Where returntype is the type of value returned by the specified operation and op is the operator being overloaded.  The op is preceded by the keyword operator.  Operator op is the function name.
Inheritance:
Inheritance allows a hierarchy of classes to be built, moving from most general to most specific.  The process involves first defining a base class, which defines those qualities common to all objects to be derived from the base.  The base is usually referred to as derived classes.  A derived class includes all features of the generic base class and then adds qualities specific to the derived class.
Ex.
//The building class is declared, it will serve as the base for two derived classes.
Class building
{
in rooms;
int floors;
int area;
public:
void set_rooms(int num);
int get_rooms( );
void set_floors(int num);
int get_floors( );
void set_area(int num);
int get_area( );
};
Because all buildings have three common features, one or more rooms, one or more floors, and a total are the building classes these components into its declaration.  The member functions beginning with set the values of the private data. The function starting with get return those values.
Constructors and Destructors:





Constructors
A constructor function is a special function that is a member of a class and has the same name as that class.  The constructor is invoked whenever an object of its associated class is created.  It is called constructor because it construct the values of data members of the class.
A constructor is declared and defined as follows:
Class integer
{
int m,n;
public:
integer(void); //constructor declared
………….
………….
};
integer::integer(void)            //constructor defined
{
m=0;n=0;
}
When a class contains a constructor like the one defined above, it is guaranteed that an object created by the class will be initialized automatically. A constructor that accepts no parameter is called the default constructor.

Ex.
#include <iostream.h>
class integer
{
int m,n;
public:
integer(int, int);          //constructor declared
void display(void)
{
cout<<”m=”<<m<<”\n”;
cout<<”n=”<<n<<”\n”;
}
};
integer::integer(int x, int y)   //constructor defined
{
m=x; n=y;
}
main( )
{
integer int1(0,100);
integer int2=integer(25,75);
cout<<”\n object1”<<”\n”;
int1.display( );
cout<<”\nobject2”<<”\n”;
int2.display( );
}
output:            //object1          m=0     n=100  object2            m=25   n=75


Destructor:
A destructor, as the name implies, is used to destroy the objects that have been created by a constructor.  Like a constructor, the destructor is a member function whose name is the same as the class name but is preceded by a tilde. Ex. The destructor for the class integer can be defined as shown below:
~integer( ) { }
A destructor never takes any argument nor does it return any value.  It will be invoked  implicitly by the compiler upon exit from the program to clean up storage that is no longer accessible.  Whenever new is used to allocate memory in the constructors, we should use delete to free that memory.

Ex.
#include<iostream.h>
int count=0;
class alpha
{
public:
alpha( )
{
count++;
count<<”\n no. of object created”<<cout;
}
~alpha( )
{
cout<<”\n no. of object destroyed”<<cout;
count--;
}
};
main( )
{
cout<<”\n\n Enter main\n”;
alpha a1,a2,a3,a4;
{
cout<<”\n\n Enter Block1\”;
alpha a5;
}
{
cout<<\n\n Enter Block2\n”;
alpha a6;
}
cout<<”\n\n Re-enter main\n”;
}

C++ Keywords:
The keywords implement specific C++ language features.  There are 63 keywords currently defined for standard C++.  They are explicitly reserved identifiers and cannot be used as names for the program variables or other user-defined program elements.
Asm                 auto                 bool                 break               ase                   catch
char                 class                 const                const_cast       continue          default
delete              do                    double             dynamic_cast  else                  enum
explicit                        export              extern              false                 float                 for
friend              goto                 if                      inline               int                    long

Friend Functions:
A friend function has access to all private and protected members of the class for which it is a friend.  To declare a friend function, include its prototype within the class, preceding it with the keyword friend.  The private members cannot be accessed from outside the class.  That is a non-member function cannot have an access to the private data of a class.  There could be a situation where we would like two classes to share a particular function.  Ex. Consider a case where two classes, manager and scientist, have been defined.  We would like to use a function income_tax( ) to operate on the objects of both these classes.  In such situations, C++ allows the common function to be made friend with both the classes, allowing the function to have access to the private data of these classes.  Such a function need not be a member of any of these classes.  The friend function of the class declared as.
Class ABC
{
……….
………
public:
………
……….
Friend void xyz(void);            //declaration
};

Ex
#include<iostream>
using namespace std;
class myclass
{
int a,b;
public:
friend int sum(myclass x);
void set_ab(int i, int j);
};
void myclass::set_ab(int i, int j)
{
a=i;
b=j;
}
// sum( ) is not a member function of any class.
int  sum(myclass x)
{
return x.a+x.b;
}
int main( )
{
myclass n;
n.set_ab(3,4);
cout<<sum(n);
return 0;
}
The sum( ) function is not a member of myclass.  It still has full access to its private members.  The sum( ) is called without the use of the dot operator.  Because it is not a member function, it does not need to be qualified with an object’s name.
Ex.
#include <iostream.h>
using namespace std;
class sample
{
int a;
int b;
public:
void setvalue( )
{ a=25; b=40;}
friend float mean(samle s);
};
float mean(sample s)
{
return float(s.a+s.b)/2.0;
}
main( )
{
sample x;
x.setvalue( );
cout<<”mean value=”<<mean(x)<<”\n”;
}

Friend Classes:

It is possible for one class to be a friend of another class.  When this is the case, the friend class and all of its member functions have access to the private members defined within the other class.
#include<iostream>
using namespace std;
class twovalues
{
int a;
int b;
public:
twovalues(int i, int j) {a=i;b=j;}
friend class min;
};
class min
{
public:
int min(twovalues x);
};
int min::min(twovalues x)
{
return x.a<x.b?x.a:x.b;
}
int main( )
{
twovalues ob(10,20);
min m;
cout<<m.min(ob);
return 0;
}

In this example, class min has access to the private variables a and b declared within the two values class.  It is critical to understand that when one class is a friend of another, it only has access to names defined within the other class.  It does not inherit the other class.  The members of the first class do not become members of the friend class.










5. Inline Functions:

There is an important feature in C++ called an inline function, you can create short functions that are not actually called their code is expanded inline at the point of each invocation.  This process is similar to using a function-like macro. One of the objectives of using functions in a program is to save some memory space, which becomes appreciable when a function is likely to be called many times.  Every time a function is called, it takes a lot of extra time tin executing a series of instructions for tasks such as jumping to the function, saving registers, pushing arguments into the stack and returning to the calling function.  To eliminate the cost of calls to small functions,
#include<iostream.h>
#include<stdio.h>
inline  int max(int a, int b)
{
return a>b?a:b;
}
int main( )
{
cout<<max(10,20);
cout<<” “<<max(99,88);
return 0;
}

Inline functions may be class member functions.

#include<iostream>
using namespace std;
class myclass
{
int a,b;
public:
void init(int i, int j);
void show( );
};
// create inline function
inline void myclass::init(int i, int j)
{
a=i;
b=j;
}
//create another inline function
inline void myclass::show( )
{
cout<<a<< “”<<b<<”\n”;
}
int main( )
{
myclass x;
x.init(10,20);
x.show( );
return 0;
}

Defining Inline Functions within a Class:
It is possible to define short functions completely within a class declaration.  When a function is defined inside a class declaration, it is automatically made into an inline function.  It is not necessary to precede its declaration with the inline keyword.
#include<iostream>
using namespace std;
class myclass
{
int a,b;
public:
// automatic inline
void init(int i, int j)
{
a=i; b=j;
}
void show( )
{
cout<<a<<””<<b<<”\n”;
}
};
int main( )
{
myclass x;
x.init(10,20);
x.show( );
return 0;
}


Static Members:

When you precede a member variable’s declaration with static, you are telling the compiler that only one copy of that variable will exist and that all objects of the class will share that variable.  Unlike regular data members, individual copies of a static member variable are not made for each object.  How many objects of a class are created, only one copy of a static data member exists.  All objects of that class use that same variable.  All static variables are initialized to zero before the first object is created.
#include <iostream>
using namespace std;
class shared
{
static int a;
int b;
public:
void set(int i, int j)
{
a=i;
b=j;
}
void show( );
};
int shared::a;//define a
void shared::show( )
{
cout<<”This is static a:”<<a;
cout<<”\n this is non-static b”<<b;
cout<<”\n”;
}
int main( )
{
shared x,y;
x.set(1,1);        // set a to 1
x.show( );
y.set(2,2);        // change a to 2
y.show( );
x.show( );
return 0;
}


Static Member Functions
Member functions may also be declared as static.  There are several restrictions placed on static member functions.  They may only directly refer to other static members of the class.  A static member function does not have this pointer.  There cannot be a static and a non-static version of the same function.  A static member function may not be virtual, finally they cannot be declared as const or volatile.
Ex.
#include<iostream>
using namespace std;
class static_type
{
static int i;
public:
static void init(int x)
{
i=x;
}
void show( )
{
cout<<i;
}
};
int main( )
{
static_type::init(100);
static_type x;
x.show( );        //display 100
return 0;
}

Arrays of Objects:
It is possible to have arrays of objects.  The syntax for declaring and using an object array is exactly the same as it is for any other type of array.
# include<iostream.h>
class c1
{
int i;
public:
void set_i(int j) {i=j;}
int get_i( ) {return i;}
};
int main( )
{
c1 ob[3];
int i;
for(i=0; i<3; i++)
ob[i].set_i(i+1);
for(i=0; i<3; i++)
cout<<ob[i].get_i( ) <<”\n”;
return 0;
}                                                           // output 1,2,3
Creating Initialized vs. Uninitialized Arrays:
A special case situation occurs if you intend to create both initialized and uninitialized  arrays of objects.  Consider the following class.
Class c1
{
int i ;
public:
c1(int j) {i=j;}
int get_i( ) { return i ;}
};
Ex.

Class c1{
Int i;
Public:
C1( ) {i=0; }    // called for non-initialized arrays
C1(int j) {i=j;}            // called for initialized arrays
Int get_i( ) {return I;}

Given this class both of the following statements are permitted.
C1 a1[3]={3,5,6};       // initialized
C1 a2[34];       // uninitialized

8. Pointers to Objects:

You can have pointers to other types of variables, you can have pointers to objects.  When accessing members of a class given a pointer to an object, use the arrow (->) operator instead of the dot operator.
Ex.
#include<iostream.h>
class c1
{
int i;
public:
c1(int j) {i=j;}
int get_i( ) {return i;}
};
int main( )
{
c1 ob(88) , *p;
p=&obj;           //get address of ob
cout<<p->get_i( );       // use -> to call get_i( )
return 0;
}

When a pointer is incremented, it points to the next element of its type.  An integer pointer will point to the next integer.  All pointer arithmetic is relative to the base type of the pointer.  The same is true of pointers to objects.
Type checking C++ pointers:
You may assign one pointer to another only if the two pointer types are compatible.  For example
Int *pi;
Float *pf;
In C++ , the following assignment is illegal
Pi=pf;  //error type mismatch






The this Pointer:
When a member function is called, it is automatically passed an implicit argument that is a pointer to the invoking object , This pointer is called this.  To understand this, first consider a program that creates a class called pwr that computes the result of a number raised to some power.
#include<iostream.h>
class pwr
{
double b;
int e;
double val;
public:
pwr(double base, int exp);
double get_pwr( ) { return val;}
};
pwr::pwr(double base, int exp)
{
b=base;
e=exp;
val=1;
if(exp==0) return;
for(;exp>0; exp--) val=val*b;
}
int main( )
{
pwr x(4.0,2), y(2.5, 1), z(5,7,0);
cout<<x.get_pwr( )<<” ”;
cout<<y.get_pwr( )<< “ “;
cout<<z.get_pwr( )<<”\n”;
return 0;
}
b=base;
means that the copy of b associated with the invoking object will be assigned the value contained the base.  The same statement can also be written like this.
this->b=base;
The this pointer points to the object that invoked pwr( ) , Thus this->b refers to that objects copy of b.  here is the entire pwr( ) function written using the this pointer.
pwr::pwr(double base, int exp)
{
this->b=base;
this->e=exp;
this->val=1;
if(exp==0) return;
for(;exp>0; exp--)
this->val=this->val*this->b;
}

Pointers to Derived Types:
A pointer of one type cannot point to an object of a different type, there is an important exception to this rule that relates only to derived classes.  Assume two classes called B and D, assume that D is derived from the base class B.  In this situation a pointer of type B* may also point to an object of type D, a base class pointer can also be used as a pointer to an object of any class derived from that base.  A base class pointer can be used to point to a derived object, the opposite is not true.  A pointer of type D* may not point to an object of type B.
#include<iostream.h>
class base
{
int i;
public:
void set_i(int num) {i=num;};
int get_i( ) {return i;}
};
class derived:public base
{
int j;
public:
void set_j(int num) {j=num;}
int get_j( ) {return j;}
};


int main( )
{
base *bp;
derived d;
bp=&d;            //base pointer points to derived object
//          access derived object  using base pointer
bp->set_i(10);
cout<<bp->get_i( )<<” “;
return 0;
}

Pointers to Class Members:
To generate a special type of pointer that points to a member of a class, not to a specific instance of that member in an object.  This sort of pointer is called a pointer to a class member or a pointer-to-member, a pointer to a member is not the same as a normal C++ pointer.  A pointer to a member provides only an offset into an object of the member’s class at which that member can be found.  Member pointers are not true pointers, the . and -> cannot be applied to them, the special pointer-to-member operators .* and ->* .



#include<iostream.h>
class c1
{
public:
c1(int i) {val=i;}
int val;
int double_val( )         { return val+val;}
};
int main( )
{
int c1::*data;              //data member pointer
int (c1::*func)( );       // function member pointer
c1 ob1(1),ob2(2);        //create objects
data=&c1::val;           //get offset of val
func=&c1::double_val;         // get offset of double_val
cout<<”here are values”;
cout<<ob1.*data<<” “<<ob2.*data<<”\n”;
cout<<”here they are doubled”;
cout<<(ob1.*func) ( )<<” “;
cout<<(ob2.*func) ( )<<”\n”;
return 0;
}

This program creates two member pointers: data and func.  When declaring pointers to members, you must specify the class and use the scope resolution operator.  The program also creates objects of c1 called ob1 and ob2, the member pointers may point to either functions or data, the program obtains the addresses of val and double_val( ).

Reference to Derived Types:
A base class reference can be used to refer to an object of a derived class.  The most common application of this is found in function parameters.  A base class reference parameter can receive objects of the base class as well as any other type derived from that base.
Restrictions to References:
There are a number of restrictions that apply to references.  You cannot reference another reference.  You cannot obtain the address of a reference.  You cannot create arrays of references.  You cannot create a pointer to a reference.  You cannot reference a bit-field.  A reference variable must be initialized when it is declared unless it is a member of a class, a function parameter, or a return value.  Null references are prohibited.

Dynamic Memory Allocation Operators:

C++ provides two dynamic allocation operators, new and delete.  These operators are used to allocate and free memory at run time.  Dynamic allocation is an important part of all programs.  C++ supports dynamic memory allocation functions, called    malloc ( ) and free().  The use of new and delete operators they have several advantages.
The new operator allocates memory and returns a pointer to the start of it.  The delete operator frees memory previously allocated using new.  The general form of new and delete are.
p_var=new type;
delete p_var;

Here p_var, is a pointer variable that receives a pointer to memory that is large enough to hold an item of type.  Since the heap is finite, it can become exhausted.  If there is insufficient available memory to fill an allocation request.  Then new will fail and a bad_alloc exception will be generated.
#include<iostream.h>
int main()
{
int *p;
try
{
p=new int;      // allocate space for an int
}
catch(bad_alloc xa)
{
cout<<”allocation failure\n”;
}
*p=100;
cout<< “At”<<p<<” “;
cout<< “is the value”<<*p<<”\n”;
delete p;
return 0;
}
This program assigns to p an address in the heap that is large enough to hold an integer.  It then assigns that memory the value 100 and displays the contents of the memory on the screen.
Initializing Allocated Memory:
You can initialize allocated memory to some known value by putting an initialize after the type name in the new statement.  The general form of new is.
p_var=new var_type(initializer);
the type of the initializer must be compatible with the type of data for which memory is being allocated.  The following program gives the allocated integer an initial value of 87
#include <iostream.h>
#include<new.h>
int main()
{
int *p;
try
{
p=new int(87);           //initialize of 87
}
catch (bad_alloc xa)
{
cout<<”allocation failure\n”;
return 1;
}
cout<<”at”<<p<<””;
delete p;
return 0;
}



Allocating Arrays:
You can allocate arrays using new by using this general form.
p_var=new array_type[size];
Here size specifies the number of elements in the array.
To free an array, use this form of delete.
Delete[]p_var’
Here, the[] informs delete that an array is being released.
For example, the next program allocates a 10 element integer array.
#include<iostream.h>
#include<new.h>
int main()
{
int *p, i;
try
{
p=new int[10];           // allocate 10 integer array
}
catch (bad_alloc xa)
{
cout<<”allocation failure\n”;
return 1;
}
for(i=0; i<10; i++)
p[i]=I;
for(i=0; i<10; i++)
cout<<;[i]<<””;
delete[]p; // release the array
return 0;
}

Allocate Objects:
You can allocate objects dynamically by using new.  When you , an object is created and a pointer is returned to it.  The dynamically created object acts just like any other object.  When it is created, its constructor function is called.  When the object is freed, its destructor function is executed.
Here is a short program that creates a class called balance that links a person’s name with his or her account balance.  Inside main() an object of type balance is created dynamically.

#include<iostream.h>
#include<new.h>
#include<cstring.h>
class balance
{
double cur_bal;
char name[80];
public:
void set(double n, char *s)
{
cur_bal=n;
strcpy(name, s);
}
void get_bal(double &n, char *s)
{
n=cur_bal;
strcpy(s, name);
}
};
int main()
{
balance *p;
char s[80];
double n;
try
{
p=new balance;
}
catch (bad_alloc xa)
{
cout<<”allocation failure\n”;
return 1;
}
p->set(12387.87, “Ralph wilson”);
p->get_bal(n,s);
cout<<s<<”is balance is”<<n;
cout<<”\n”;
delete p;
return 0;
}



The nothrow Alternative:
In C++ it is possible to have new return null instead of throwing an exception when an allocation failure occurs.  This form of new is most useful when you are compiling older code with a modern C++ compiler.  It is also valuable when you are replacing calls to malloc( ) with new.
P_var=new(nothrow)type;
Here p_var is a pointer variable of type.  The nothrow form of new works like the original version of new from years ago.  Since it returns null on failure, it can be dropped, older code without having to add exception handling.
#include<iostream.h>
#include<new.h>
int main( )
{
int *p, i;
p=new(nothrorw) int[32];     // use notrhrow option
if(!p)
{
cout<<”Allocation failure\n”;
return 1;
}
for(i=0; i<32; i++) p[i]=i;
for(i=0; i<32; i++) cout<<p[i]<<” “ ;
delete [ ] p;     // free the memory
return 0;
}

The Placement Forms of new and delete:
There is a special form of new, called the placement form, that can be used to specify an alternative method of allocating memory.  It is primarily useful when overloading the new operator for special circumstances.  The general form.
P_var=new(location)type;
Here location specifies an address that is simply returned by new.  There is also a placement form of delete, which is used to free memory allocated by the placement form of new.

No comments:

Post a Comment