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