Sunday 8 July 2012

Function Overloading in c++


Function Overloading:-


In function overloading, the function is said to be overloaded when same name is given to different functions. However, the functions will differ at least in any one of the these. The number of parameters, the data type of parameters, the order of appearance these three together are referred to as the function signature. While overloading a function, the return types of the function
need not differ.

1. Functions differ in function signature.
2. Return types of functions need not differ.


#include<conio.h>
#include<iostream.h>

class arithmetic
{
public:
 void calc(int num1)
{
Cout<<”\n\n Square of a given number:”<<num1*num1<<endl;
}
Void calc(int num1,int num2)
{
 Cout<<”\n\nMultiplication of given number is: “<<num1*num2<<endl;
}
};
Void main()
{
Clrscr();
Arithmetic a;
a.calc(5);
a.calc(6,7);
getch();
}


Output :

Square of the given number is : 25
Multiplication of given number is: 42

The code depicts function overloading. There are two functions with the same name calc. In the main function, when the function calc is invoked using the object a, depending up on the type and number of parameters, the compiler binds the call to the function. Hence, when calc(5) is called, the compiler checks for the function matching the parameter type. So calc(int num l) will be invoked and parameter will be passed to the function at runtime and output displayed. Similarly, when calc(6,7) is called, it looks for the same function with two integers as parameter and bind the respective function to the call.



Operator Overloading


Operating overloading allows you to pass different variable types to the same function and produce different results. In this article Ben gives us the low-down on operator overloading in C++.Operator overloading is common-place among many efficient C++ programmers. It allows you to use the same function name, but as different functions.



If this sounds confusing, then just think about it like this: you can use the same function name for as many functions as you like, but you *must* pass different variable types to each function.

In this article I will show you exactly what function overloading is, and how you can get it to work for you in C++. You should have an intermediate knowlede of C++. Any compiler will do, as I will only use ISO-standard compliant syntax.

Operator Overloading - Definition


This can be a weird subject for some, especially those with a strong Java background, or another language that doesn't support this feature. It can be confusing even for excellent programmers. But it is a strong feature of C++ that, if mastered, can yield some increased productivity in programming.

We all know that an operator can be used in mathematical expressions:

int z=x+y;
float g=3.14*g;

Now wouldn't it be nice to use operators on our own objects to do what we want? For example, a string class could use + to concatenate, or a Throttle class could use the ++ and -- operators to increase or decrease throttle position. The operators can be programmed to do whatever we want them to.

        However, some words of caution. Operator overloading provides NO additional functionality to your code. It just compiles to normal function calls. It's even written out like normal function calls. It is mainly for aesthetics. There is, however, one extremely useful set of operators to overload that makes life much easier: the streaming operators, which I will cover at the end.

           Second, you should NOT use operator overloading for unobvious relationships. Using + to concatenate two strings intuitively makes sense to most programmers, so it's easy to use it like that. But how would you define string1*string2? or string1^string2? It isn't very clear what that means. So use caution when considering adding operators to your objects.

Sample Object

For my sample object, I'm going to implement a matrix. This won't be a full-scale implementation of every imaginable matrix operation, but it should be enough to cover the basics of operator overloading, and maybe whet your appetite to complete the implementation for other operations (dot product, inverse, determinant, etc.).

In order to completely encapsulate a matrix within a class, we actually need two classes: Row and Matrix.

So let's start with Row:

template<class T>
class Row {
public:
Row(int cols=0):row(NULL) {SetRowSize(cols);}
~Row() {SetRowSize(0); }
Row(const Row &r):row(NULL) {
SetRowSize(r.numCols);
for (int i=0;i<numCols;i++)
row[i]=r.row[i];
}

void SetRowSize(int n) {
if(row) delete[] row;
if (n>0) {
row=new T[n];
memset(row,0,sizeof(T)*n/sizeof(char));
}
else row=NULL;
numCols=n;
}

int size() { return numCols;}
private:
int numCols;
T* row;
};

Let's look at this before continuing on. Notice that I'm making it a template class. This is so you can have a matrix of all the usual numerical types, as well as any type you want to define yourself. The only requirement for the type is that it must have the +, -, and * operators defined on it. We'll get into how to do that. If you don't understand templates, you can think of all of the T's as ints for now.

SetRowSize() deletes any old data, and allocates space for new data, unless we set the number of columns to 0, in which case it merely deletes the data. This lets us use this function for construction, destruction, and dynamic modification in one method. Nifty, eh? The call to memset() just zeroes out the array after figuring out how many bytes the row uses and dividing this by the size of character, because memset() works in terms of chars.

I also defined a copy constructor, which will come in handy quite a bit, as we'll see later on when we copy matrices.

Overloading[]
OK, let's overload our first operator: []

Yes, that's one operator. The array-access operator. It makes perfect sense here, because we have a linear array of objects we would like to access. Let's add this definition to our Row class:

T& operator[](int column) {
assert(column<numCols);
return row[column];
}

The arguments to our brackets are going to be integers specifying the index of the item we want, so that will be the function's arguments. Notice the syntax: [ReturnType] operator[Op]([argument list]). We do an assertion to make sure we're accessing memory within the array's bounds. If all is OK, we return a reference to the object. Why a reference instead of a value? It won't make much of a difference in a case like this:

Row<int> r(1);//1x1 matrix

int a=r[0];

a will get the value of r[0] whether a reference or a value is returned. However, if we return a reference, we can then change the value in the row from outside the class, using the [] accessor operator, like so:

Row<float> r(1);

r[0]=3.142;
float pi=r[0];

Operator Overloading in C++ Overloading =


The only other operator we need to overload is assignment (=). When overloading assignment, we must keep in mind that the object we're assigning to must already exist, and it is that object's operator= method which will be called.

Row& operator=(const Row& r) {
SetRowSize(r.numCols);
for (int i=0;i<numCols;i++)
row[i]=r.row[i];
return *this;
}

Again we return a reference, but this time it's a reference to itself. First we set the size of the current row equal to that of the source row, then we copy its values. There is an important note here. Notice that I'm using [] on the primitive T array itself--NOT the overloaded []s of Row. Remember that Row's [] returns a reference, thus if we had written row[i]=r[i], we would get a row that references the exact same data in memory, so that when we changed one the other would change--this isn't what we want at all, so we need to access the raw data in the Row class.

Now we can write code like this:

Row<double> r1(5);
Row<double> r2;//creates an empty row
Row<double> r3(2);
r2=r1;
r3=r1;//overwrites previous row information to contain same info as r1

Matrices are Made of Many Rows
Now that we have a working Row, we can combine rows into a matrix. Let's start with this basic definition:

template<class T>
class Matrix {
public:
Matrix(int rows=0, int cols=0): matrix(NULL) {
SetSize(rows,cols);
}
Matrix(const Matrix& m): matrix(NULL) {
SetSize(m.numRows,m.numCols);
for (int r=0;r<numRows;r++)
matrix[r]=Row<T>(m.matrix[r]);//assign to primitive array, NOT overloaded []--to get a copy
}
void SetSize(int rows, int cols) {
if (rows) delete[]matrix;
if (cols > 0 && rows >0) {
matrix=new Row<T>[rows];
for (int i=0;i<rows;i++)
matrix[i].SetRowSize(cols);
}
else
rows=NULL;
numCols=cols;numRows=rows;
}
int GetCols() { return numCols;}
int GetRows() { return numRows;}

private:
int numCols, numRows;
Row<T>* matrix;

};

This follows very closely the basic form of the Row class. The only item of interest is when we declare and allocate a matrix: we must specify the type, T, after the class name.

First let's implement the same operators we did on the Row class:

Row<T>& operator[](int index) {
assert(index<numRows);
return matrix[index];
}

Matrix& operator=(const Matrix& m) {
SetSize(m.numRows,m.numCols);
for (int r=0;r<numRows;r++)
matrix[r]=Row(m.matrix[r]);//assign to primitive array, NOT overloaded []--to get a copy
return *this;
}

The most important part of this code is the return type of operator[]. It returns a reference to a Row of type T. This little fact allows us to use the Matrix class like this:

Matrix<int> a(2,2);

a[0][0]=2;
a[0][1]=4;
a[1][0]=8;
a[1][1]=16;

That is, we can refer to Matrix objects now with exactly the same notation as primitive 2-D arrays in C++: array[row][column]. Our operator overloading is faking it well enough to keep a consistent interface with analogous structures, but add much more functionality and safety. Isn't this cool?

The = operator works the same way as in Row. It sets the size of the current Matrix to that of the source, and then copies all of the objects to the current Matrix. Now we can do the following:

Matrix<__int64> m(1000,1000);
Matrix<__int64> n=m;


Operator Overloading in C++

Let's do some more interesting things with these matrices now. There are a number of mathematical operations that can be performed on a matrix, the simplest perhaps is addition. Addition of matrices requires that they both have the same dimensions. The resulting matrix is made by simply adding each number in the same position in each matrix and putting the answer in the same position as the two operands.

[1 0] [4 3] [5 3]
[2 1] + [-1 0] = [1 1]

Since addition creates a new matrix, we don't want to return a reference, but an actual matrix object. Here's what the code looks like:

const Matrix operator+( const Matrix& m) {
assert(numCols==m.numCols && numRows==m.numRows);
Matrix theMatrix(numRows,numCols);
for (int r=0;r<numRows;r++)
for (int c=0;c<numCols;c++)
theMatrix[r][c]=matrix[r][c]+m.matrix[r][c];
return theMatrix;
}

This adds the current matrix to the matrix in argument m. We first assure that the dimensions are equivalent, then create a new matrix with the same dimensions as the sources. It is then a simple matter of adding the two sources, and returning the new matrix. Notice that we perform the actual math on the types that make up each row.

Matrix<float> a(2,2);
Matrix<float> b(2,2);

Matrix<float> c(2,3);

Matrix<float> d=a+b;

Matrix<float> e=a+c;//will fail assertion, abort program

It is just as easy to define subtraction:

const Matrix operator-( const Matrix& m) {
assert(numCols==m.numCols && numRows==m.numRows);
Matrix theMatrix(numRows,numCols);
for (int r=0;r<numRows;r++)
for (int c=0;c<numCols;c++)
theMatrix[r][c]=matrix[r][c]-m.matrix[r][c];
return theMatrix;
}

Overloading += and -=
+= and -= are operators that both add and change the current object, so the code to describe it is a combination of +/- and =. We'll return a reference again because we don't want to create a new object, but just modify the existing one, which called the function. We'll just add whatever is currently in it to the other matrix, and return a reference to itself:

Matrix& operator+=(const Matrix& m) {
assert(numCols==m.numCols && numRows==m.numRows);
for (int r=0;r<numRows;r++)
for (int c=0;c<numCols;c++)
matrix[r][c]+=m.matrix[r][c];
return *this;
}

Matrix& operator-=( const Matrix& m) {
assert(numCols==m.numCols && numRows==m.numRows);
for (int r=0;r<numRows;r++)
for (int c=0;c<numCols;c++)
matrix[r][c]-=m.matrix[r][c];
return *this;
}

We can now expand our repertoire to include the following possibilities:

Matrix<int> a(2,1);
Matrix<int> b(2,1);

a+=b;
a-=b;



CLASS TEMPLATES
C++ Class Templates are used where we have multiple copies of code for different data types with the same logic. If a set of functions or classes have the same functionality for different data types, they becomes good candidates for being written as Templates.
   One good area where this C++ Class Templates are suited can be container classes. Very famous examples for these container classes will be the STL classes like vector, list etc., Once code is written as a C++ class template, it can support all data types. Though very useful, It is advisable to write a class as a template after getting a good hands-on experience on the logic (by writing the code with normal data types). There are cases where we need specialization for writing optimized code for specific data types. This C++ class template Specialization article gives a brief description.
   This article describes how to declare, define and use the C++ Class Templates in practice. This tries to build a very preliminary Queue, using the STL::Vector container class. This code is written and tested with Microsoft Visual C++ 5.00.

Declaring C++ Class Templates:

   Declaration of C++ class template should start with the keyword template. A parameter should be included inside angular brackets. The parameter inside the angular brackets, can be either the keyword class or typename. This is followed by the class body declaration with the member data and member functions. The following is the declaration for a sample Queue class.
//Sample code snippet for C++ Class Template
template <typename T>
class MyQueue
{
         std::vector<T> data;
      public:
         void Add(T
const &d);
         void Remove();
         void Print();
};

   The keyword class highlighted in blue color, is not related to the typename. This is a mandatory keyword to be included for declaring a template class.

Defining member functions - C++ Class Templates:

   If the functions are defined outside the template class body, they should always be defined with the full template definition. Other conventions of writing the function in C++ class templates are the same as writing normal c++ functions.
template <typename T> void MyQueue<T> ::Add(T const &d)
{
     data.push_back(d);
}

template <typename T> void MyQueue<T>::Remove()
{
      data.erase(data.begin( ) + 0,data.begin( ) + 1);
}

template <typename T> void MyQueue<T>::Print()
{
     std::vector <
int>::iterator It1;
     It1 = data.begin();
     for ( It1 = data.begin( ) ; It1 != data.end( ) ; It1++ )
          cout << " " << *It1<<endl;

}
 

   The Add function adds the data to the end of the vector. The remove function removes the first element. These functionalities make this C++ class Template behave like a normal Queue. The print function prints all the data using the iterator.

Full Program - C++ Class Templates:

//C++_Class_Templates.cpp

#include <iostream.h>
#include <vector>

template <typename T>
class MyQueue
{
     std::vector<T> data;
   public:
     void Add(T const &);
     void Remove();
     void Print();
};

template <typename T> void MyQueue<T> ::Add(T const &d)
{
     data.push_back(d);
}

template <typename T> void MyQueue<T>::Remove()
{
     data.erase(data.begin( ) + 0,data.begin( ) + 1);
}

template <typename T> void MyQueue<T>::Print()
{
     std::vector <
int>::iterator It1;
     It1 = data.begin();
     for ( It1 = data.begin( ) ; It1 != data.end( ) ; It1++ )
        cout << " " << *It1<<endl;

}
//Usage for C++ class templates
void main()
{
     MyQueue<
int> q;
     q.Add(1);
     q.Add(2);

     cout<<"Before removing data"<<endl;
     q.Print();

     q.Remove();
     cout<<"After removing data"<<endl;
     q.Print();
}

Advantages of C++ Class Templates: 

  • One C++ Class Template can handle different types of parameters.
  • Compiler generates classes for only the used types. If the template is instantiated for int type, compiler generates only an int version for the c++ template class.
  • Templates reduce the effort on coding for different data types to a single set of code.
  • Testing and debugging efforts are reduced.

FUNCTION TEMPLATES


C++ Function templates are those functions which can handle different data types without separate code for each of them. For a similar operation on several kinds of data types, a programmer need not write different versions by overloading a function. It is enough if he writes a C++ template based function. This will take care of all the data types.
   There are two types of templates in C++, viz., function templates and class templates. This article deals with only the function templates.
   There are lot of occasions, where we might need to write the same functions for different data types. A favorite example can be addition of two variables. The variable can be integer, float or double. The requirement will be to return the corresponding return type based on the input type. If we start writing one function for each of the data type, then we will end up with 4 to 5 different functions, which can be a night mare for maintenance.
   C++ templates come to our rescue in such situations.  When we use C++ function templates, only one function signature needs to be created. The C++ compiler will automatically generate the required functions for handling the individual data types. This is how a programmer's life is made a lot easier.

C++ Template functions - Details:  

   Let us assume a small example for Add function. If the requirement is to use this Add function for both integer and float, then two functions are to be created for each of the data type (overloading).
   int Add(int a,int b) { return a+b;} // function Without C++ template
   float Add(float a, float b) { return a+b;} // function Without C++ template

   If there are some more data types to be handled, more functions should be added.
   But if we use a c++ function template, the whole process is reduced to a single c++ function template. The following will be the code fragment for Add function.
   template <class T>
   T Add(T a, T b) //C++ function template sample
   {
     return a+b;
   }

  This c++ function template definition will be enough. Now when the integer version of the function, the compiler generates an Add function compatible for integer data type and if float is called it generates float type and so on.
   Here T is the typename. This is dynamically determined by the compiler according to the parameter passed. The keyword class means, the parameter can be of any type. It can even be a class.   

C++ Template functions - Applicability:

   C++ function templates can be used wherever the same functionality has to be performed with a number of data types. Though very useful, lots of care should be taken to test the C++ template functions during development. A well written c++ template will go a long way in saving time for programmers.

Abstract classes

An abstract class is a class that is designed to be specifically used as a base class. An abstract class contains at least one pure virtual function. You declare a pure virtual function by using a pure specifier (= 0) in the declaration of a virtual member function in the class declaration.
The following is an example of an abstract class:
class AB {
public:
  virtual void f() = 0;
};
Function AB::f is a pure virtual function. A function declaration cannot have both a pure specifier and a definition. For example, the compiler will not allow the following:
struct A {
  virtual void g() { } = 0;
};
You cannot use an abstract class as a parameter type, a function return type, or the type of an explicit conversion, nor can you declare an object of an abstract class. You can, however, declare pointers and references to an abstract class. The following example demonstrates this:
struct A {
  virtual void f() = 0;
};
 
struct B : A {
  virtual void f() { }
};
 
// Error:
// Class A is an abstract class
// A g();
 
// Error:
// Class A is an abstract class
// void h(A);
A& i(A&);
 
int main() {
 
// Error:
// Class A is an abstract class
//   A a;
 
   A* pa;
   B b;
 
// Error:
// Class A is an abstract class
//   static_cast<A>(b);
}
Class A is an abstract class. The compiler would not allow the function declarations A g() or void h(A), declaration of object a, nor the static cast of b to type A.
Virtual member functions are inherited. A class derived from an abstract base class will also be abstract unless you override each pure virtual function in the derived class.
For example:
class AB {
public:
  virtual void f() = 0;
};
 
class D2 : public AB {
  void g();
};
 
int main() {
  D2 d;
}
The compiler will not allow the declaration of object d because D2 is an abstract class; it inherited the pure virtual function f()from AB. The compiler will allow the declaration of object d if you define function D2::g().
Note that you can derive an abstract class from a nonabstract class, and you can override a non-pure virtual function with a pure virtual function.
You can call member functions from a constructor or destructor of an abstract class. However, the results of calling (directly or indirectly) a pure virtual function from its constructor are undefined. The following example demonstrates this:
struct A {
  A() {
    direct();
    indirect();
  }
  virtual void direct() = 0;
  virtual void indirect() { direct(); }
};
The default constructor of A calls the pure virtual function direct() both directly and indirectly (through indirect()).
The compiler issues a warning for the direct call to the pure virtual function, but not for the indirect call.


Inheritance


        New classes created from existing classes
        Absorb attributes and behaviors
        Derived class
         Class that inherits data members and member functions from a previously defined base class
        Single inheritance
         Class inherits from one base class
        Multiple inheritance
         Class inherits from multiple base classes
        Types of inheritance
         public: private: protected:

Inheritance: Base and Derived Classes
         Base and derived classes
        Often an object from a derived class (subclass) is also an object of a base class (superclass)
         A rectangle is a derived class in reference to a quadrilateral and a base class in reference to a square
         Inheritance examples



















Base and Derived Classes
         Implementation of public inheritance
            class CommissionWorker : public Employee {
   ...
};
   Class CommissionWorker inherits from class Employee
   friend functions not inherited
   private members of base class not accessible from derived class


   protected access
        Intermediate level of protection between public and private inheritance
        Derived-class members can refer to public and protected members of the base class simply by using the member names
        Note that protected data “breaks” encapsulation

         Derived class member functions
        Cannot directly access private members of their base class
         Maintains encapsulation
        Hiding private members is a huge help in testing, debuggi
        ng and correctly modifying systems
 























Overriding Base-Class Members in a Derived Class
         To override a base-class member function
        In the derived class, supply a new version of that function with the same signature
         same function name, different definition
        When the function is then mentioned by name in the derived class, the derived version is automatically called
        The scope-resolution operator may be used to access the base class version from the derived class
public, private, and protected Inheritance


Direct and Indirect Base Classes

         Direct base class
        Explicitly listed derived class’s header with the colon (:) notation when that derived class is declared
class HourlyWorker : public Employee
   Employee is a direct base class of HourlyWorker
         Indirect base class
        Not listed in derived class’s header
        Inherited from two or more levels up the class hierarchy
class MinuteWorker : public HourlyWorker
   Employee is an indirect base class of MinuteWorker













Using Constructors and Destructors in Derived Classes

         Base class initializer
        Uses member-initializer syntax
        Can be provided in the derived class constructor to call the base-class constructor explicitly
         Otherwise base class’s default constructor called implicitly
        Base-class constructors and base-class assignment operators are not inherited by derived classes
         Derived-class constructors and assignment operators, however, can call base-class constructors and assignment operators


         A derived-class constructor
        Calls the constructor for its base class first to initialize its base-class members
        If the derived-class constructor is omitted, its default constructor calls the base-class’ default constructor
         Destructors are called in the reverse order of constructor calls
        So a derived-class destructor is called before its base-class destructor





Multiple Inheritance

         Multiple Inheritance
        Derived-class inherits from multiple base-classes
        Encourages software reuse, but can create ambiguities





Dynamic Polymorphism


Objectives

*        Implement the concept of binding
*        Use virtual functions
*        Use pure virtual functions to create abstract classes
*        Implement dynamic polymorphism by using late binding

Dynamic Polymorphism

*        Refers to any entity changing its form, depending on circumstances

Binding

*        Is the process of associating a function with a class by identifying the type of the object or pointer that is used to invoke the function

Dynamic Binding

*        Is done during runtime
*        Is also called late binding

Virtual Function

*        Is a function that is declared as virtual in a base class and is redefined by a derived class

Using Virtual Functions

Example:
class Employee
{
.
.
virtual int calc_net_salary();
.
.
};
class Contract:public Employee
{
.
.
int calc_net_salary();
.
.
.
};
class Direct_Contract: public Contract
{
.
.
int calc_net_salary();
.
.
             };
Pure Virtual Function

*         Is a function without a body
*         Is created by adding the notation ‘=0’ to the virtual function declaration

            Example:
                        virtual int calc_net_salary()=0;

Abstract Class

*         Is a class containing one or more pure virtual functions 
*         Is used as a base class for deriving specific classes of the same kind

Static vs Dynamic Polymorphism (Contd.)

*         Dynamic polymorphism
Is considered more flexible
Is based on overriding principles, which, therefore, is purely class scope and is based on inheritance




Streams I/O:-

Objectives
In this lesson, you will learn to:
*        Define the stream class hierarchy
*        Identify the stream insertion and extraction operators
*        Use the stream classes for file input and output
*        Differentiate between text and binary file input and             output
*        Apply the following functions for opening and closing files:
3        open()
3        close()
*        Use the open mode bits
*        Randomly access data files


Stream Class Hierarchy :-




Features of Stream Classes
Stream Classes:
*        Form a powerful set of classes that can be modified, extended, or expanded to incorporate user-defined data types or classes
*        Are fully buffered to reduce disk access
*        Encapsulate their internal working from the user
*        Offer a rich set of error-handling facilities
Stream Insertions
*         Are output operations for which the functions are    defined in the ostream class
Stream Insertion Operators
*         Are defined in the ostream class
*         The operator “<<” is called the inserter
Stream Extractions
*         Are input operations for which the functions are                  defined in the istream class
           
Stream Extraction Operators
*         Are defined in the istream class and are used to       receive data from the input device
*         The operator “>>”, called the extractor, accepts any             built-in data type passed as arguments
The get() and getline() Functions
*         Are used to read a complete string from the input    stream
*         Recognize white spaces
*         The get() function
            Syntax:
            cin.get(char *str, int len, char delim =                                                            '\n');
*         The getline() function
            Syntax:
            cin.getline(char *str, int len, char                                                        delim = '\n');
File Input and Output Using Built-in Data Types
*        Integer Input and Output
            Example:
            #include <fstream>
            int main()
            {
            ofstream outobj("INT.TST");
            outobj << 25 << ' ' << 4567 << ' ' << 8910;
return 0;
            }
*        Character input and output
             Example:
            #include <fstream>
                        int main()
                        {
            ofstream out("STR.TST");
            out << "This is a test string";
return 0;
                        }         
File Input and Output Using Objects
Example:
#include<fstream.h>
class student
            {
private:
                        int iReg_no;char cName[20];
public:
                        void setRegno();
                        void setName();
                        int getRegno();
                        char *getName();
            };
void main()
{
                        ofstream Sfil(“studfile.dat”);
                        char ch;
                        student Svar;
                        Svar.setRegno();
                        Svar.setName();
                        Sfil<<Svar.getRegno()
                                    <<“ ”<<Svar.getName();
                        Sfil.close(); //Closes the open file
cout<< “\n Do you want to view the                                                  contents of a file (y/n)?”;
                        cin>>ch;
                        if(ch== ‘y’)
                        {
                                    ifstream Sfil(“studfile.dat”);
                                    char ireg;char nam[20];
                                    Sfil>>ireg>>nam;
                                    cout<<“\n Registration Number is ”                           <<ireg;
                                    cout<<“\n Student Name is ” <<nam;
                        }
            }

Binary Input and Output (Contd.)
3        The write function
                         Syntax:
                                    write(char* addr, int size)
*        File input and output using abstract data types
3        read() and write() functions are used to read or write user-defined objects on a file
The open() Function
*        Is used to open a file
            Example:
            ifstream Ifil;    //creates an                                         //unopened input stream
            Ifil.open("DATA.DAT");       //associates                              //the stream to a file
The close() Function
*        Is used to close a file
            Example:
            ofstream Ofil;
            Ofil.open("DATA.DAT");
            ...
            ...
            Ofil.close();
Open Mode Bits
*        Are defined in the ios class
*        Are bits that are associated with the opening of files
*        Represent the mode in which the file is opened



















The get Pointer
*        Specifies the location in the file where the next read operation will occur

The put Pointer
*        Specifies the location in the file where the next write operation will occur

The seekg() Function
*        Helps to control the get pointer
*        Moves the get pointer to an absolute address within the file or to a certain number of bytes from a particular position
*        Takes two arguments:
3        The number of bytes to move
3        The reference in the file from where the pointer                    has to be repositioned
                                                Example:
                                                ifstream iFil;
                                                iFil.seekg(10,ios::beg);
The tellg() Function
*        Helps to control the get pointer
*        Can be used to find the current position of the get file pointer in a file
*        Does not take any arguments
                                                Example:
                                                int iPosition=iFil.tellg();
The seekp() Function
*        Helps to control the put pointer
*        Moves the put pointer to an absolute address within the file or to a certain number of bytes from a particular position

The tellp() Function
*        Helps to control the put pointer
*        Can be used to find the current position of the put file pointer in a file





















ject&(�]n b ��Q 0qY d as follows:
long nBytes = BufferedOutput::bytecount;
For the static member to exist, it is not necessary that any objects of the class type exist. Static members can also be accessed using the member-selection (. and –>) operators. For example:
BufferedOutput Console;

long nBytes = Console.bytecount;
In the preceding case, the reference to the object (Console) is not evaluated; the value returned is that of the static object bytecount.
Static data members are subject to class-member access rules, so private access to static data members is allowed only for class-member functions and friends. These rules are described in Member-Access Control. The exception is that static data members must be defined in file scope regardless of their access restrictions. If the data member is to be explicitly initialized, an initializer must be provided with the definition.
The type of a static member is not qualified by its class name. Therefore, the type of BufferedOutput::bytecount is long.

 

 

 

 

 

9. The this pointer:-

The keyword this identifies a special type of pointer. Suppose that you create an object named x of class A, and class A has a nonstatic member function f(). If you call the function x.f(), the keyword this in the body of f() stores the address of x. You cannot declare the this pointer or make assignments to it.
A static member function does not have a this pointer.
The type of the this pointer for a member function of a class type X, is X* const. If the member function is declared with the const qualifier, the type of the this pointer for that member function for class X, is const X* const.
A const this pointer can by used only with const member functions. Data members of the class will be constant within that function. The function is still able to change the value, but requires a const_cast to do so:
void foo::p() const{    
member = 1;                       // illegal    
const_cast <int&> (member) = 1;   // a bad practice but legal 
}
A better technique would be to declare member mutable.
If the member function is declared with the volatile qualifier, the type of the this pointer for that member function for class X is volatile X* const. For example, the compiler will not allow the following:
struct A {
  int a;
  int f() const { return a++; }
};
The compiler will not allow the statement a++ in the body of function f(). In the function f(), the this pointer is of type A* const. The function f() is trying to modify part of the object to which this points.
The this pointer is passed as a hidden argument to all nonstatic member function calls and is available as a local variable within the body of all nonstatic functions.
For example, you can refer to the particular class object that a member function is called for by using the this pointer in the body of the member function. The following code example produces the output a = 5:
#include <iostream>
using namespace std;
 
struct X {
private:
  int a;
public:
  void Set_a(int a) {
 
    // The 'this' pointer is used to retrieve 'xobj.a'
    // hidden by the automatic variable 'a'
    this->a = a;
  }
   void Print_a() { cout << "a = " << a << endl; }
};
 
int main() {
  X xobj;
  int a = 5;
  xobj.Set_a(a);
  xobj.Print_a();
}
In the member function Set_a(), the statement this->a = a uses the this pointer to retrieve xobj.a hidden by the automatic variable a.
Unless a class member name is hidden, using the class member name is equivalent to using the class member name with the this pointer and the class member access operator (->).
The example in the first column of the following table shows code that uses class members without the this pointer. The code in the second column uses the variable THIS to simulate the first column's hidden use of the this pointer:

10. Dynamic Memory Allocation and Deallocation:-

Until now, in all our programs, we have only had as much memory available as we declared for our variables, having the size of all of them to be determined in the source code, before the execution of the program. But, what if we need a variable amount of memory that can only be determined during runtime? For example, in the case that we need some user input to determine the necessary amount of memory space.
The answer is dynamic memory, for which C++ integrates the operators new and delete.

Operators new and new[]

In order to request dynamic memory we use the operator new. new is followed by a data type specifier and -if a sequence of more than one element is required- the number of these within brackets []. It returns a pointer to the beginning of the new block of memory allocated. Its form is:
pointer = new type
pointer = new type [number_of_elements]
The first expression is used to allocate memory to contain one single element of type type. The second one is used to assign a block (an array) of elements of type type, where number_of_elements is an integer value representing the amount of these. For example:
Int *bobby;
Bobby = new int[5];
this case, the system dynamically assigns space for five elements of type int and returns a pointer to the first element of the sequence, which is assigned to bobby. Therefore, now, bobby points to a valid block of memory with space for five elements of type int.
The first element pointed by bobby can be accessed either with the expression bobby[0] or the expression *bobby. Both are equivalent as has been explained in the section about pointers. The second element can be accessed either with bobby[1] or *(bobby+1) and so on...
You could be wondering the difference between declaring a normal array and assigning dynamic memory to a pointer, as we have just done. The most important difference is that the size of an array has to be a constant value, which limits its size to what we decide at the moment of designing the program, before its execution, whereas the dynamic memory allocation allows us to assign memory during the execution of the program (runtime) using any variable or constant value as its size.
The dynamic memory requested by our program is allocated by the system from the memory heap. However, computer memory is a limited resource, and it can be exhausted. Therefore, it is important to have some mechanism to check if our request to allocate memory was successful or not.
C++ provides two standard methods to check if the allocation was successful:
One is by handling exceptions. Using this method an exception of type bad_alloc is thrown when the allocation fails. Exceptions are a powerful C++ feature explained later in these tutorials. But for now you should know that if this exception is thrown and it is not handled by a specific handler, the program execution is terminated.
This exception method is the default method used by new, and is the one used in a declaration like:
bobby = new int[5]; // if it fails an exception is thrown
The other method is known as nothrow, and what happens when it is used is that when a memory allocation fails, instead of throwing a bad_alloc exception or terminating the program, the pointer returned by new is a null pointer, and the program continues its execution.
This method can be specified by using a special object called nothrow, declared in header <new>, as argument for new:
bobby = new (nothrow) int [5]; 

In this case, if the allocation of this block of memory failed, the failure could be detected by checking if bobby took a null pointer value:
int * bobby;
bobby = new (nothrow) int [5];
if (bobby == 0) {
  // error assigning memory. Take measures.
  };
This nothrow method requires more work than the exception method, since the value returned has to be checked after each and every memory allocation, but I will use it in our examples due to its simplicity. Anyway this method can become tedious for larger projects, where the exception method is generally preferred. The exception method will be explained in detail later in this tutorial.

Operator delete and delete[]

Since the necessity of dynamic memory is usually limited to specific moments within a program, once it is no longer needed it should be freed so that the memory becomes available again for other requests of dynamic memory. This is the purpose of the operator delete, whose format is:

delete pointer;
delete [] pointer;
The first expression should be used to delete memory allocated for a single element, and the second one for memory allocated for arrays of elements.
The value passed as argument to delete must be either a pointer to a memory block previously allocated with new, or a null pointer (in the case of a null pointer, delete produces no effect).

// rememb-o-matic
#include <iostream>
#include <new>
using namespace std;
 
int main ()
{
  int i,n;
  int * p;
  cout << "How many numbers would you like to type? ";
  cin >> i;
  p= new (nothrow) int[i];
  if (p == 0)
    cout << "Error: memory could not be allocated";
  else
  {
    for (n=0; n<i; n++)
    {
      cout << "Enter number: ";
      cin >> p[n];
    }
    cout << "You have entered: ";
    for (n=0; n<i; n++)
      cout << p[n] << ", ";
    delete[] p;
  }
  return 0;
}
Output:- 
 
How many numbers would you like to type? 5
Enter number : 75
Enter number : 436
Enter number : 1067
Enter number : 8
Enter number : 32
You have entered: 75, 436, 1067, 8, 32,

Notice how the value within brackets in the new statement is a variable value entered by the user (i), not a constant value:
p= new (nothrow) int[i];
But the user could have entered a value for i so big that our system could not handle it. For example, when I tried to give a value of 1 billion to the "How many numbers" question, my system could not allocate that much memory for the program and I got the text message we prepared for this case (Error: memory could not be allocated). Remember that in the case that we tried to allocate the memory without specifying the nothrow parameter in the new expression, an exception would be thrown, which if it's not handled terminates the program.
It is a good practice to always check if a dynamic memory block was successfully allocated. Therefore, if you use the nothrow method, you should always check the value of the pointer returned. Otherwise, use the exception method, even if you do not handle the exception. This way, the program will terminate at that point without causing the unexpected results of continuing executing a code that assumes a block of memory to have been allocated when in fact it has not.




11. Exception Handling:-
Exceptions are run-time anomalies, such as division by zero, that require immediate handling when encountered by your program. The C++ language provides built-in support for raising and handling exceptions. With C++ exception handling, your program can communicate unexpected events to a higher execution context that is better able to recover from such abnormal events. These exceptions are handled by code that is outside the normal flow of control.
The try, catch, and throw Statements
The following syntax shows a try block and its handlers:
try {
   // code that could throw an exception
}
[ catch (exception-declaration) {
   // code that executes when exception-declaration is thrown
   // in the try block
}
[catch (exception-declaration) {
   // code that handles another exception type
} ] . . . ]
// The following syntax shows a throw expression:
throw [expression]
 Remarks
The C++ language provides built-in support for handling anomalous situations, known as exceptions, which may occur during the execution of your program. The try, throw, and catch statements implement exception handling. With C++ exception handling, your program can communicate unexpected events to a higher execution context that is better able to recover from such abnormal events. These exceptions are handled by code that is outside the normal flow of control. The Microsoft C++ compiler implements the C++ exception handling model based on the ANSI C++ standard.
C++ also provides a way to explicitly specify whether a function can throw exceptions. You can use exception specifications in function declarations to indicate that a function can throw an exception. For example, an exception specification throw(...) tells the compiler that a function can throw an exception, but doesn't specify the type, as in this example:
void MyFunc() throw(...) {
   throw 1;
}
For more information, see Exception Specifications.
The code after the try clause is the guarded section of code. The throw expression throws (raises) an exception. The code block after the catch clause is the exception handler, and catches (handles) the exception thrown by the throw expression. The exception-declaration statement indicates the type of exception the clause handles. The type can be any valid data type, including a C++ class. If the exception-declaration statement is an ellipsis (...), the catch clause handles any type of exception, including C exceptions and system- or application-generated exceptions such as memory protection, divide by zero, and floating-point violations. Such a handler must be the last handler for its try block.
The operand of throw is syntactically similar to the operand of a return statement.
Execution proceeds as follows:
1.                  Control reaches the try statement by normal sequential execution. The guarded section within the try block is executed.
2.                  If no exception is thrown during execution of the guarded section, the catch clauses that follow the try block are not executed. Execution continues at the statement after the last catch clause following the try block in which the exception was thrown.
3.                  If an exception is thrown during execution of the guarded section or in any routine the guarded section calls (either directly or indirectly), an exception object is created from the object created by the throw operand. (This implies that a copy constructor may be involved.) At this point, the compiler looks for a catch clause in a higher execution context that can handle an exception of the type thrown (or a catch handler that can handle any type of exception). The catch handlers are examined in order of their appearance following the try block. If no appropriate handler is found, the next dynamically enclosing try block is examined. This process continues until the outermost enclosing try block is examined.
4.                  If a matching handler is still not found, or if an exception occurs while unwinding, but before the handler gets control, the predefined run-time function terminate is called. If an exception occurs after throwing the exception, but before the unwind begins, terminate is called.
5.                  If a matching catch handler is found, and it catches by value, its formal parameter is initialized by copying the exception object. If it catches by reference, the parameter is initialized to refer to the exception object. After the formal parameter is initialized, the process of unwinding the stack begins. This involves the destruction of all automatic objects that were constructed (but not yet destructed) between the beginning of the try block associated with the catch handler and the exception's throw site. Destruction occurs in reverse order of construction. The catch handler is executed and the program resumes execution following the last handler (that is, the first statement or construct which is not a catch handler). Control can only enter a catch handler through a thrown exception, never via a goto statement or a case label in a switch statement.
The following is a simple example of a try block and its associated catch handler. This example detects failure of a memory allocation operation using the new operator. If new is successful, the catch handler is never executed:
// exceptions_trycatchandthrowstatements.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main() {
   char *buf;
   try {
      buf = new char[512];
      if( buf == 0 )
         throw "Memory allocation failure!";
   }
   catch( char * str ) {
      cout << "Exception raised: " << str << '\n';
   }
}
The operand of the throw expression specifies that an exception of type char * is being thrown. It is handled by a catch handler that expresses the ability to catch an exception of type char *. In the event of a memory allocation failure, this is the output from the preceding example:
Exception raised: Memory allocation failure!
The real power of C++ exception handling lies not only in its ability to deal with exceptions of varying types, but also in its ability to automatically call destructor functions during stack unwinding, for all local objects constructed before the exception was thrown.
The following example demonstrates C++ exception handling using classes with destructor semantics:
 Example
// exceptions_trycatchandthrowstatements2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
void MyFunc( void );
class CTest {
public:
   CTest() {};
   ~CTest() {};
   const char *ShowReason() const { 
      return "Exception in CTest class."; 
   }
};
 
class CDtorDemo {
public:
   CDtorDemo();
   ~CDtorDemo();
};
 
CDtorDemo::CDtorDemo() {
   cout << "Constructing CDtorDemo.\n";
}
 
CDtorDemo::~CDtorDemo() {
   cout << "Destructing CDtorDemo.\n";
}
 
void MyFunc() {
   CDtorDemo D;
   cout<< "In MyFunc(). Throwing CTest exception.\n";
   throw CTest();
}
 
int main() {
   cout << "In main.\n";
   try {
       cout << "In try block, calling MyFunc().\n";
       MyFunc();
   }
   catch( CTest E ) {
       cout << "In catch handler.\n";
       cout << "Caught CTest exception type: ";
       cout << E.ShowReason() << "\n";
   }
   catch( char *str )    {
       cout << "Caught some other exception: " << str << "\n";
   }
   cout << "Back in main. Execution resumes here.\n";
}
 
In main.
In try block, calling MyFunc().
Constructing CDtorDemo.
In MyFunc(). Throwing CTest exception.
Destructing CDtorDemo.
In catch handler.
Caught CTest exception type: Exception in CTest class.
Back in main. Execution resumes here.
 Comments
Note that in this example, the exception parameter (the argument to the catch clause) is declared in both catch handlers:
catch( CTest E )
// ...
catch( char *str )
// ...
You do not need to declare this parameter; in many cases it may be sufficient to notify the handler that a particular type of exception has occurred. However, if you do not declare an exception object in the exception-declaration, you will not have access to that object in the catch handler clause.
A throw-expression with no operand re-throws the exception currently being handled. Such an expression should appear only in a catch handler or in a function called from within a catch handler. The re-thrown exception object is the original exception object (not a copy). For example:
try {
   throw CSomeOtherException();
}
catch(...) {  // Handle all exceptions
   // Respond (perhaps only partially) to exception
   throw;       // Pass exception to some other handler
}
 
 

1 comment:

  1. This comment has been removed by a blog administrator.

    ReplyDelete

Write your openion about my blog spot..To get automatic facebook updates like my Pagehttps://www.facebook.com/shivashankar4u ..It takes only 1 min to write the comment and to like the page.. Thanks.