<Previous Lesson

Introduction to Programming

Next Lesson>

Lesson#45

Lesson 45

Summary


Example (continued)
Assignment Operator Function
Addition Operator Function
Plus-equal Operator Function
Overloaded Plus Operator Function
Minus Operator Function
Multiplication Operator Function
Insertion and Extraction Operator Function
exercise
Rules for Programming
Variables and Pointers
Arrays
Loops and decisions
Classes and Object
Garbage Collection
Truth Table
Structured Query Language


Example
(continued)

 

This is a sequel of the discussion on ‘matrix class’ made in the previous lectures.

 

Assignment Operator Function


Before going into minute details, we will talk about the assignment operator of this class.
This operator occupies very important place in the field of programming. When we want
to write code like a = b; where a and b both are matrices, the assignment operator attains
a critical role as our class does dynamic memory allocation. Here we don’t know whether
the size of a and b will be the same or not. If these are of different size, then it will be
Page 588
better to reallocate the memory. So it warrants the existence of some checks and
balances. At first, we look at the declaration line of the assignment operator, it is written
below.
const Matrix & operator = (const Matrix &m);
The declaration line states that it must return a reference to a matrix. Why do we want to
return a matrix? The return of the matrix is necessary to enable us write the statement i.e.
a = b = c;
We know, in C and C++ languages, every expression has a value of its own.
Now if we write a = b ; it will mean that the whole action will have a value. This value
itself will be a reference to a matrix. On the other hand, we have made it const. In other
words, the reference that is being returned is a constant.
Whenever we return a reference of a thing that thing can become on left-hand side of an
assignment statement, which can lead to some very funny behavior. If we write (a = b) =
c ;
It will result in the execution of the statement, a = b. It will return a value that is a
reference to a matrix. This reference will be assigned the value of c. this means that some
minor things can take place. We will like to have parentheses only on right hand side. It
is advisable not to do an assignment to the reference that is being returned. To avoid this,
we write const with it. Thus, we get the efficiency as reference is being returned. We also
enjoy safety due to the fact that no value can assign to this reference in the same
statement. Due to the reference returned, we can write the statement like a = b = c ;
Let’s have a look on the next implication i.e. the size of the matrix. Whenever there is
dynamic memory allocation in a class, we have to check against self-assignment. Selfassignment
means statements like a = a ;. If we take ordinary variables, say integer,
writing i = i ; is quiet right. But if we write something like a = a ; it will be possible to
free the memory of object on the left hand side as it is doing some dynamic memory
allocation. Now we can assign new memory and copy the right hand side in it. If we write
a = a;
it will lead to a very tricky situation. This means that we, at first, delete it (the lefthand
side), as right hand side is the same object with same memory, so it is also deleted.
Then, we try to copy the right hand side that has been deleted. So we must check against
self-assignment. While dealing with the code of the assignment operator, we will first
check whether it is for the self-assignment or not. To ascertain it, we will write the
following line.
if( &m != this)
This way, the self-assignment check has been carried out. In case of not finding selfassignment,
the programmer will have to do further process..
After checking the self-assignment, the program checks the size of both the matrices and
sees whether these are the same or different. If their size is same, then it will copy the
matrix of right hand side element-by-element in the matrix on left-hand side. But if their
size is different in terms of number of rows or columns, then we have to create a new
matrix for the left-hand side. This code is similar to the one that we wrote in the
constructor. We free the memory and reallocate the memory of the correct size. This size
Page 589
is equal to the size of the matrix on right hand side. After re-allocating the memory, we
readjust the number of rows and columns of the lef- hand side object. So we write it as
numerous = m.numRows ;
numCols = m.numCols ;
While defining rows and columns, we execute a for loop and copy the elements of right
hand side at corresponding positions on left hand side. This way, we define the
assignment operator, which can be used in different functions. Here, we can write
statement like a = b which will work properly. The same thing is applied to our main
code when we come to a client function of the class. The code of the function of
assignment operator is written as below.
const Matrix & Matrix :: operator = ( const Matrix & m )
{
if( &m != this)
{
if (numRows != m.numRows || numCols != m.numCols)
{
delete [] elements;
elements = new (double *) [m.numRows];
for (int i = 0; i < m.numRows; i++)
elements[i]=new double[m.numCols ];
}
numRows = m.numRows;
numCols = m.numCols;
for ( int i=0; i<numRows; i++)
{
for(int j=0; j<numCols; j++)
{
elements[i][j] = m.elements[i][j];
}
}
}
return *this;
}

Addition Operator Function


Now we will discuss the addition operator. We have discussed a variety of addition
operators. We come across one of these while writing a + b where a and b are matrices.
While adding two matrices, it is ensured that these are compatible. It means that the
matrices are conformable for addition. Their number of rows and columns should be
equal. The code, we have just, written is very simple. It first checks whether the matrices
are compatible. If so, it does the element-to-element addition. If these are not compatible,
it returns the old matrix. Here the thing to remember is, what is being returned? The
addition operator returns a new matrix after adding two matrices. The matrices, which
Page 590
were added, remain the same. So, if we add two matrices a and b, these will remain as it
is and addition operator will return a resultant matrix by adding them. Therefore, if we
find the matrices are compatible, a new matrix is defined. Having defined the new matrix,
we can apply some tricks to it. We can define the new matrix by using copy constructor.
So a complete matrix will be copied to it. This is reflective from the following statement.
Matrix temp (m) ;
When we a copy of one matrix, i.e. temp, the elements of the other matrix are added to it.
We do this with a loop. After this, temp is returned. This temporary matrix (temp) which
was created in the addition operator, is returned. However, its reference can not be
returned. Here we have to return a matrix, ignoring the problem of efficiency. So this
whole matrix will be copied on the stack and assigned wherever it is needed. If we have
written c = a + b ; it will be assigned to c. The things where the reference or matrix is
being returned, should be carried out carefully. It is important for us to know what thing
should be returned to where, and what is its usage and behavior? The code of the addition
operator function is written in the program as below.
Matrix Matrix::operator + ( Matrix &m ) const
{
// Check for conformability
if(numRows == m.numRows && numCols == m.numCols)
{
Matrix temp(*this);
for (int i = 0; i < numRows; i++)
{
for (int j = 0; j < numCols; j++)
{
temp.elements[i][j] += m.elements[i][j];
}
}
return temp ;
}
Matrix temp(*this);
return temp;
}

Plus-equal (+=) Operator Function


Now we will discuss the += operator. Whenever a programmer writes a += b, he will
come across a different scenario as compared to the one witnessed in the case of the
addition operator. In a way, now ‘a’ itself is being changed. So if a is going to change,
we can return a reference to a. The conformability check remains the same as in ordinary
addition. That means both matrices must have the same number of rows and columns.
There is no need of creating a temporary matrix. Here we can return reference to lefthand
side matrix. Here one finds that there is reuse and efficiency in the code. The +=
operator is defined as under.
Page 591
const Matrix & Matrix::operator += (Matrix &m)
{
*this = *this + m;
return *this;
}

Overloaded plus Operator Function


Next concept to be discussed the overloading of the overloaded plus (+) operator. It is
very simple. If we want to add a double variable in a matrix, there will be no problem of
conformability. All we need to do is add a value to every element. Here we are doing a +
d
(a is a matrix while d is a double). Here, a will not change. A new matrix will be
returned by adding the value of d to the elements of a. So it is not returning a reference,
but a matrix. If it is returning a matrix, it must return a matrix that is created inside this
function. Thus, we can use copy constructor and write
Matrix temp (* this) ;
In this matrix temp, we add the value of d by a nested loop and return it. This way, the
addition of a matrix with a double variable is defined. The code of it is given below.
Matrix Matrix::operator + ( double d ) const
{
Matrix temp(*this);
for (int i = 0; i < numRows; i++)
{
for (int j = 0; j < numCols; j++)
{
temp.elements[i][j] += d;
}
}
return temp ;
}
Next function is d + a (i.e. double variable + matrix). There is a double variable and not a
matrix on left hand side, leaving no option for having it as a member function. It is a
friend function and defined outside the class. We don’t use the scope resolution operator
(::) with it. It is defined as an ordinary stand-alone function. It still returns a matrix .So it
is written as
Matrix operator + (double d, Matrix &m)
Two arguments are passed to it that are the variables on left and right side of the operator.
The remaining code is almost the same as that of a + d, and is written as below.
Matrix operator + (double d, Matrix &m)
{
Page 592
Matrix temp(m);
for(int i=0; i< temp.numRows; i++)
{
for(int j=0; j<temp.numCols; j++)
{
temp.elements[i][j] += d;
}
}
return temp;
}

Minus Operator (-) Function


The same discussion of plus (+) operator applies to the minus (-) operator as both are
identical. We see the difference between these operators when we do a + d. In case of
addition, it will be the same as that of d + a. However, while dealing with minus case,
the result of a - d will be obviously different from the result of d - a.

Multiplication Operator (*) Function


The most complicated operator out of all these arithmetic manipulators for matrices is the
multiplication (*) operator. How do we multiply two matrices together? We have already
discussed it while defining matrices. We have discussed that the size of the resultant
matrix will be the number of rows of the first matrix multiplied by the number of
columns of second matrix. We also have discussed the method to calculate the element of
the resultant matrix. Obviously, before doing this, we check the conformability of the
matrices for multiplication. The code of the function for * operator is defined as below.
Matrix Matrix::operator* ( const Matrix& m)
{
Matrix temp(numRows,m.numCols);
if(numCols == m.numRows)
{
for ( int i = 0; i < numRows; i++)
{
for ( int j = 0; j < m.numCols; j++)
{
temp.elements[i][j] = 0.0;
for( int k = 0; k < numCols; k++)
{
temp.elements[i][j] += elements[i][k] *
m.elements[k][j];
}
}
}
}
return temp;
}
Page 593
The multiplication of a matrix with a double is nothing more complicated as that of doing
addition of a matrix with a double. So code used in both cases is similar. In the case of
division of a matrix by a double, the only thing that differs is that while dividing a matrix
with a double, we have to check the division by zero. After having that little check, we
divide the matrix. Without going for some complex method, we simply return the original
matrix if it encounters a division by zero. Mathematically speaking, it is not correct. We
should actually throw an exception so that program should stop in such a case. But we do
not throw an exception and return the original matrix without trying to divide it by zero.
So our program does not generate a run time error. There may be logical errors. So we
have to be careful in such a case.

Insertion (<<) and Extraction (>>) Operator Function


The last set of functions that we have defined is the stream insertion (<<) and extraction
(>>) operators. These operators may be taken as the example of code reuse. We have
already defined input and output functions for this class. These input and output can
handle matrices with files or on screen. Now we want an operator to write cin >> m ;
where m is an object of type Matrix. It means that we have to read from the keyboard and
store these values in the matrix m. Inside the code, we can reuse the input function and
write m.input in the function body. This is the overloaded stream extraction operator. The
only difference is that we have to return a reference to the stream. Thus it is a two- line
function and is a good example of code reuse. We have written the input function, which
can be used here. Same thing applies if we have to take input from the file and put it into
matrix m. We have declared these functions as friend functions and in the following their
code is written
istream & operator >> ( istream & is, Matrix & m)
{
m.input(is);
return is;
}
We will now use the input function, written to take input from file.
ifstream & operator >> ( ifstream & is, Matrix & m)
{
m.input(is);
return is;
}
Similarly, the pair of output functions can be reused to overload the stream insertion
operator.
ostream & operator << ( ostream & os, Matrix & m)
{
m.output();
Page 594
return os;
}
And for the file output the code is as follows.
ofstream & operator << ( ofstream & os, Matrix & m)
{
m.output(os);
return os;
}

Exercise


Now you should study and understand this whole code of the class and use it. Its use is
very simple. You can write the main function and in it write
Matrix m (3,3) ;
When you will execute it, a matrix of three rows and three columns will be created and
values of it will be zero. To display this matrix on the screen, you can write
m.output ;
It will display a properly formatted matrix on the screen. Similarly you can define other
matrices and can get their values from the keyboard. You can multiply them and see that
multiplication is done only if the matrices are conformable for multiplication. Similarly,
addition will work only if the matrices are conformable for addition. You can write a
little test program. You should also try to extend the class by adding new functions and
features into it. In the code, there are not proper error messages. You can write code to do
more error checking and to display proper error messages wherever an error encounters.
It is very simple to change the whole class from double to int. More complicated one
would may be used to write a template for this class. In the class, wherever there is
double
, you will write <T> there and on the top, there will be template <class T>. The
remaining things will almost look identical. You will have to take care in friend
functions. So there is a lot of stuff you can do with it.

Review


Now we will review the different topics of the course briefly and some discussion in
respect of languages and programming. In the beginning of the course, we came across a
few programming guidelines. We have read about design recipe. Then we went on and
developed the way of thinking.
To begin with the review of the previously discussed subjects, we will now talk about the
rules of programming.

Rules for Programming


Page 595
We need simply three constructs to solve any problem.
1) Things should be executed sequentially. That means the statements are executed in a
sequence i.e. the second statement follows the first and so on.
2) We need to have a decision. The decision means if something is true, the program
executes it. Otherwise, it tries doing something else. So there is simple decision or if-else
decision.
3) The third construct is loop, which is a repetition structure that performs the same task
repeatedly with different values.
So the availability of sequences, decisions and loops can help us write any program. The
code, we write, should be short and concise. It need to be self-contained and
understandable. Comments should be placed liberally. The comments should explain the
logic, not the mechanics. Try to avoid fancy programming. The indentation of the code
has no means programmatically as it does not mean any thing at all. What actually
matters is how you structure the code using braces and semicolons i.e. the structure of the
language. Otherwise, C and C++ are free-format languages. We can write the whole code
in a single line. But it will be very difficult to read. We format our code so that it could be
read easily. So indentation is for us, not for the compiler. Similarly, any language does
not dictate it. On the other hand, if we put our code inside braces and blocks, it will
ensure a logical syntax.

Variables and Pointers


After constructs, the concept of variables and pointers holds very important position in
programming. The variable is a name for a value. It is like a label on a box in the
memory, which contains a value. We can use this label to manipulate the value, instead of
using the address of the memory that contains the value. There are different types of
variables.
We discussed earlier, the pointers are much more specific to C and C++. A pointer is an
address of a location in the memory. We also have talked about their manipulations.

Arrays


An array is a type of data structure. We use an array to store multiple values of the same
data type. In C, C++ and FORTRAN languages, the arrays are of the same data type i.e.
every element of the array is of the same data type. There can be an array of integers, an
array of characters and so on. We cannot have elements of different types in an array.
There are the languages in which we can have arrays of mixed-type. FoxPro is the
quotable example in this regard. We can store in a variable whatever we want. For
example if we write a = 3 then a is a numerical value. On other hand suppose, if we write
a = “This is a string”
. Here ‘a’ becomes a character string. Similarly in Visual Basic,
there is a data type, called variant that can store data of all kinds. So remember that
Page 596
whenever we talk of arrays and variables, different languages behave differently. There
are no hard and fast rules.

Loops and Decisions


The loops and decisions are ‘bread and butter’ for a programmer.
While talking about decisions, we read that in C and C++ languages, there is a simple if
statement. There is also ‘if-else statement’. We can write a big structure by using the
nested if-else statements. There is also switch statement. These statements (if, if-else and
switch) are language specific. Almost all the modern programming languages provide a
decision structure. The exact syntax of which can be got from language reference.
While talking about repetition structure, we come across the concept of loops. The loops
are of three different types in C ++. These include while, do-while and for loop. There is
a subtle difference between them. While using the while loop, if its condition is false at
the start, its body will not execute even once. In other words a while loop executes zero
or more times. On the other hand, if we write a do-while loop, the block of code written
after the do will execute at least once. So a do-while loop executes one or more times.
The for loop is more like the while loop. It will execute zero or more times. Every loop
has a basic structure that is independent of the language. There is some initialization, a
condition that is tested for the execution of the loop. Then there is the body of the loop in
which it performs its task. These are almost same in the languages. But the syntax is
particular to the language.

Classes and Objects


In this course, we discussed, only the concept of, classes and objects. The study of
rudiments of classes and objects can help us understand the difference between
implementation and interface besides comprehend the concept of the encapsulation. We
combine the data and code to form an object. It is a new type of variable, a user-defined
data type. It not only has its data structure but also the code that manipulates the data.
The major advantage of data hiding and encapsulation is that it makes every thing tested,
debugged and ready to use. When we come in the main program, which uses these
classes or objects, our code becomes very simple. We can reuse this code repeatedly.
When we put all of this together, the concept of doing object-oriented programming
becomes clear. How can a class be made from another class? We will talk about
polymorphism in the course of object oriented programming. It can determine what
function is to call at the execution time of the program not at the compile time. These are
very important and powerful methods. There will be whole idea of thinking objects. Here
we only covered mechanics. When we were talking about mechanics, we have to
understand how can we implement a member function and a member operator. We use
the sequences, decisions and repetition structures while writing the member or friend
functions. So we build on our previous knowledge and introduce the concepts of classes
and objects.

Garbage Collection


Page 597
The whole concept of using objects and their notation which is object.member, where
member could be a data type or a function, that is what we have been exercising. We also
mentioned that we could have pointers to objects. During the manipulation of the data
variable or data member with pointers, we use the arrow (->) notation rather than the dot
(.) notation. The concept of pointers is very important but quite limited to C and C++.
The modern languages, for example JAVA, describe pointers as dangerous. We can go
anywhere in the memory and can change a value. There is another problem with pointers,
which is that these could be pointing to nowhere. For example, we allocate memory and
de-allocate it there or in some other function, without reassigning a new memory to the
pointer that was pointing to that memory. Thus, a dangling pointer is there that points to
nothing. There is also reverse case of it that we assign a memory through a pointer where
the pointer is destroyed, the memory remains allocated and is wasted. To address these
things, there are only references in JAVA instead of pointers. JAVA gives the concept of
garbage collection with the use of references. Due to this garbage collection, we are free
from the headache of de-allocating the memory. We allocate and use the memory. When
it is no longer in use, JAVA automatically deletes (frees) it through garbage collection.
But in C and C++ languages, we have to take care of de-allocating the memory. In
classes where we use dynamic memory, we have to provide destructors to free this
memory. The languages keep evolving, new constructs will keep evolving in existing or
new languages. So the foundations of our knowledge must be strong. We have to know
what is programming. We have to know how can we take the essence of a problem by
analyzing it. We should repeat the design recipe as many times as needed.

Truth Table


There are some areas where the decision structures become very complicated.
Sometimes, we find it difficult to evaluate a complicated logical expression. Sometimes
the logic becomes extremely complicated so that even writing it as a simple syntax
statement in any language. It becomes complicated to determine what will be evaluated in
what way. We know the concept of truth table. The truth tables are very important. These
are still a tool available for analyzing logical expressions. We will read logic design in
future, which is actually to do with chips and gates. How we put these things together. In
logic design, there are certain techniques that are known as minimization techniques.
These are used to make a big circuit with the use of minimum chips. These minimization
techniques deal with Boolean algebra i.e. logic. These techniques are also used in
programming. So we should keep breadth in our vision while maintaining a horizontal
integration. We should always think outside the box. There is a way of thinking for us as
programmers. We always look at problems, slice and dice them and come up with
solutions. Programming as a skill is infact important. It helps us think, from a logical
perspective. How can we do it is something else. We can get it from the reference books
of the language or from online help in the compiler. This part that how can we do is
always changing. New languages will be evolved for our help. On the other hand, what is
to be done depends on our logical skills and fundamental knowledge. We have to develop
this thing.

Structured Query Language


Page 598
In the business world, most of the programming is database-oriented. In today’s
databases, like Oracle and SQL Server, a different kind of language is used. These are the
languages that are called as structured query languages i.e. SQL. SQL, is so important
that a standard has been developed for it. So there is an ANSI standard for this language.
There is a major difference between SQL and the conventional language. The SQL by
law says ‘tell me what do you want and I will determine how to do it’. Whereas in our
conventional languages like C or C++, we have to tell the languages what we want to do
and how to do it. These are differentiated in the terminology like third generation
languages and fourth generation languages.
There are optimizers built in those languages. Optimizers mean how a query or question
can be executed more efficiently. In the same way, there are optimizers in our compilers.
When we write the code, the compiler looks into it to determine how this code can be
executed more efficiently. The modern compilers do a large optimization. Different
software companies or computer manufacturers write the compilers. The standard is the
same for writing compilers. The difference is that how much fast the executable version
of a program executes and how much memory it uses, when compiled by different
compilers. The speed and memory usage is the two yard sticks of output code.
The fundamentals are important. Keeping of a breadth of vision is also critically
important. We have to constantly keep up with literature, keep up with new development,
and experiment with more and more new tools.
Talking about languages is not that important. However, talking about programming is
critically more important. If we have a sound fundamental knowledge, no new language
can frighten us. We will never feel over powered by any new language. The fundamentals
can become strong only by practicing more and experimenting to the maximum.

Page 208: [1] Deleted a 1/1/1997 2:24:00 AM


employees can calculate the salary. Similarly, do we need to save the output or just print
it. What will happen if we get some error during printing?

Page 208: [2] Deleted a 1/1/1997 2:24:00 AM


Today we will discuss text file handling.

Page 208: [3] Deleted a 1/1/1997 2:24:00 AM


disk. First we need to open that file.

Page 211: [4] Deleted a 1/1/1997 2:24:00 AM


Name Salary Department
Aamir 12000 Sales
Amara 15000 HR
Adnan 13000 IT
Afzal 11500 Marketing

Page 211: [5] Deleted a 1/1/1997 2:24:00 AM


/*
* This program reads from a txt file “myfile.txt” which contains the
* employee information
*/
#include <iostream.h>
#include <fstream.h>
main()
{
ifstream inFile; // Handle for the input file
char inputFilename[] = "myfile.txt"; // file name, this file is in the current directory
inFile.open(inputFilename); // OPening the file
// checking that file is successfuly opened or not
if (!inFile)
{
cout << "Can't open input file named " << inputFilename << endl;
exit(1);
}
char name[50]; // used to read name of employee from file
char sal[10]; // used to read salary of employee from file
char dept[30]; // used to read dept of employee from file
// Reading the complete file word by word and printing on screen
while (!inFile.eof())
{
inFile >> name >> sal >> dept;
cout << name << "\t" << sal << " \t" << dept << endl;
}
inFile.close();
}

Page 212: [6] Deleted a 1/1/1997 2:24:00 AM


Name Salary Department
Aamir 12000 Sales
Amara 15000 HR
Adnan 13000 IT
Afzal 11500 Marketing

Page 213: [7] Deleted a 1/1/1997 2:24:00 AM


out Open a file or stream for insertion (output).

Page 213: [8] Deleted a 1/1/1997 2:24:00 AM


in Open a file or stream for extraction (input
app Append rather than truncate an existing file. Each insertion
(output) will be written to the end of the file

Page 213: [9] Deleted a 1/1/1997 2:24:00 AM


trunc Truncate existing file (default behavior)

Page 213: [10] Deleted a 1/1/1997 2:24:00 AM


ate Opens the file without truncating, but allows data to be
written anywhere in the file

Page 213: [11] Deleted a 1/1/1997 2:24:00 AM


binary Treat the file as binary rather than text. A binary file has
data stored in internal formats, rather than readable text
format. For example, a float would be stored as its internal
four byte representation rather than as a string.


<<<<<< THE END >>>>>


<Previous Lesson

Introduction to Programming

Next Lesson>

Home

Lesson Plan

Topics

Go to Top

Copyright © 2008-2013 zainbooks All Rights Reserved
Next Lesson
Previous Lesson
Lesson Plan
Topics
Home
Go to Top