C Lecturenotes
C Lecturenotes
Introduction to OOPS
Procedural Languages
Figure 1-4
The
corporate
parad
Concepts of OOPS
Physical objects
Elevators in an elevator control program
Automobiles in a traffic flow simulation
Countries in an economics model
Aircraft in an air traffic control system
Elements of the computer user environment
Windows
Menus
Graphics objects (lines, rectangles, circles)
The mouse, keyboard, disk drives, printer
• Data-storage constructs
Customized arrays
Stacks
Linked lists
Binary trees
• Human entities
Employees
Students
Customers
Salespeople
• Collections of data
An inventory
A personnel file
A dictionary
A table of the latitudes and longitudes of
world cities
• User-defined data types
Time
Angles
Complex numbers
Points on the plane
States and Abilities
The match between programming objects and
real-world objects is the happy result of
combining data and member functions. This is
an important concept, so let’s look at it
another way. Many real-world objects, at least
the interesting ones, have both a state
(characteristics that can change) and abilities
(things they can do). For example, an
elevator could be in the following state: It’s
on the 3rd floor, it contains four passengers,
and the passengers have pushed buttons for
the 7th, 11th, and 15th floors. The elevator
might also have the following abilities: It can
go down, it can go up, it can open and close
its doors, it can query other elevators to see
where they are, and it can calculate where it
should go next.
Classes
What is Abstraction?
Enhanced Security:
Abstraction gives access to data or details that are needed
by users and hide the implementation details, giving
enhanced security to application.
Easier Replacement:
With the concept of abstraction in object-oriented
programming language, it is possible to replace code
without recompilation. This makes the process easier and
saves time for users.
Modular Approach:
In object-oriented programming language C++, the
abstraction concept helps users to divide the project
application into modules and test each of them separately.
Then all modules are integrated and ultimately tested
together. This approach makes the application
development easier.
There are various ways of achieving abstraction in object-
oriented programming language C++. One approach is to
take modular based code that is broken apart into smaller
segments, known as functions. This functional or modular
approach helps the code to be reused again and again
when needed. For example, a programmer might write a
function for computing an average and another
programmer might write a function for computing salary.
These functions can be reused when needed, by anyone.
The modular based approach helps to centralize all data
of a similar type, under the control of a type module.
Defining module types allow the module to be an abstract
data type. In many other programming languages, there is
a small drawback associated with the approach to
accessing module type.
Data abstraction
Encapsulation
Inheritance
Reusability
C++ and C
C++ is derived from the C language. Strictly
speaking, it is a superset of C: Almost every
correct statement in C is also a correct
statement in C++, although the reverse is not
true. The most important elements added to
C to create C++ are concerned with classes,
objects, and object-oriented programming.
(C++ was originally called “C with classes.”)
However, C++ has many other features as
well, including an improved approach to I/O
and a new way to write comments. Figure 3-2
shows the relationship between C and C++.
Message
A running program is a pool of objects where objects are
created, destroyed and interacting. This interacting is
based on messages which are sent from one object to
another asking the recipient to apply a method on itself.
To give you an understanding of this communication, let's
come back to the class Integer. In our pseudo
programming language we could create new objects and
invoke methods on them. For example, we could use
Integer i; /* Define a new integer object */
i.setValue(1); /* Set its value to 1 */
to express the fact, that the integer object i should set its
value to 1. This is the message ``Apply method setValue
with argument 1 on yourself.'' sent to object i. We notate
the sending of a message with ``.''. This notation is also
used in C++; other object-oriented languages might use
other notations, for example ``- ''.
Sending a message asking an object to apply a method is
similar to a procedure call in ``traditional'' programming
languages. However, in object-orientation there is a view
of autonomous objects which communicate with each
other by exchanging messages. Objects react when they
receive messages by applying methods on themselves.
They also may deny the execution of a method, for
example if the calling object is not allowed to execute the
requested method.
In our example, the message and the method which
should be applied once the message is received have the
same name: We send ``setValue with argument 1'' to
object i which applies ``setValue(1)''.
Definition (Message) A message is a request to an object
to invoke one of its methods. A message therefore
contains
the name of the method and
the arguments of the method.
Consequently, invocation of a method is just a reaction
caused by receipt of a message. This is only possible, if
the method is actually known to the object.
Definition (Method) A method is associated with a class.
An object invokes a method as a reaction to receipt of a
message.
Dynamic Binding
Program Organization
Variable Declarations
Functions
Namespaces
The larger a program is, the greater the
danger of name clashes, that is, a single
name being used—inadvertently—to refer to
several different things. This is a particular
problem in multifile programs, where files
may have been created by different
programmers or different companies. For
example, suppose a class alpha is defined in
a file A:
// file A
class alpha
{ };
In another file, which will eventually be linked
with file A, there is also a specification for a
class that— unbeknownst to the creators of
file A—has been given the same name:
// file B
class alpha
{ };
The resulting name clash will cause linker
errors. Programmers might then try to fix the
problem by renaming one of the alpha
classes. However, there’s an easier way. A
recent revision to the draft ANSI C++
standard introduces a new solution to this
problem: namespaces. A namespace is a
section of a program specified by the keyword
namespace and enclosed in brackets. A name
used within a namespace does not have
global visibility; instead, its scope is limited to
the namespace.
Lecture No. 5
Basic program construction: data types, variables,
functions and statements
Characters
Characters are stored in variables of type
char. The statement
char ch3;
creates space in memory for a character and
names it ch3. To store a particular character
in this variable, use a statement like
ch3 = ‘a’;
Character constants, such as ‘a’, ‘B’, ‘&’ or
‘4’, are surrounded by single quotes.
Assignment Operator
Escape Sequences
Unsigned Integers
Floating Point
Whitespace
C++ doesn’t mind if you put extra spaces into
a program line. You can use them to align
things so they’re easier to read. You could say
float pi_float = 3.1415;
double pi_double = 3.14159265358979;
long double pi_long_double =
3.141592653589793238;
You can put as many spaces, tabs, and new
lines as you want in your program. These
characters constitute
whitespace, and the C++ compiler ignores
whitespace in almost all situations.
Programmers use whitespace to make the
program easier for humans to follow.
Comments
Introduction to Input/Output
String Constants
The text “This text will appear on the
screen.” is called a string constant. A string
constant is surrounded by double quotes
(unlike a character constant, which is
surrounded by single quotes). The entire
statement, as with all C++ statements, is
terminated with a semicolon.
You can output numerical constants the same
way. The statement
cout << 27;
causes a 27 to appear on the screen, whereas
cout << 123.45;
displays 123.45.
You can display the values of variables as well
as numbers. For example, this code displays
2.7:
float fvar1 = 2.7;
cout << fvar1;
More than one value can be displayed with a
single cout statement, using multiple put to
operators:
float height = 2.7;
cout << “It is ” << height << “ meters
high.”;
This would produce the output
It is 2.7 meters high.
You can also reformat such a statement so
that the put to operators line up vertically,
thus making the statement easier to read:
cout << “It is”
<< height
<< “meters high.”;
Or you could use three separate cout
statements to produce the same output.
Formatting Output
Escape Sequences
Stream I/O
Old-Style C I/O
Member Functions
Recording a Sale
Displaying Data
Arithmetic Operators
In the SoldOneDog() function, shown above,
you used the subtraction operator (-) to
subtract one from two values. C++ includes
the usual four arithmetic operators plus a
fifth, less common one, as shown in Table 6-1.
Table 6-1 Arithmetic operators
Operator - Purpose
+ - Addition
- Subtraction
- Multiplication
/ - Division
% - Remainder
The first four operators perform familiar
operations. The remainder operator, % (also
called the modulus operator), is used to
calculate the remainder when one integer is
divided by another. Thus the expression
20 % 3 evaluates to 2, because 20 divided by
3 is 6, with a remainder of 2.
You can use any of the arithmetic operators
just as you would in normal arithmetic or
algebra or most other programming
languages. They are called binary operators
because they operate on two quantities. That
is, expressions involving them have the form
alpha+beta, where the + operates on alpha
and beta. Of course, you can make arithmetic
expressions as complicated as you want. For
example,
c = (f-32) * 5 / 9;
converts a temperature in Celsius to one in
Fahrenheit. Use parentheses so the
subtraction will be carried out first, despite its
lower precedence. (The term precedence
refers to the order in which operations are
carried out. The * and / operators have
higher precedence than the + and -
operators.)
In C++, it’s perfectly all right to mix different
arithmetic types in the same expression. For
example, in the above statements, f might
be type int and c might be type float. The
compiler would not complain. Instead, it
would automatically convert the types
appropriately before carrying out the
arithmetic.
Relational Operators
Precedence
Simple Decisions
The if Statement
Fine-Tuning Loops
Fig 7-5
Fig 7-6
Fig 7-7
Fig 7-8
while Loops
do Loops
for Loops
Nested Loops
You can nest one loop inside another. For
example, the following program fragment
prints a 10 by 10 square of Xs,
like this:
xxxxxxxxxx
xxxxxxxxxx
xxxxxxxxxx
xxxxxxxxxx
xxxxxxxxxx
xxxxxxxxxx
xxxxxxxxxx
xxxxxxxxxx
xxxxxxxxxx
xxxxxxxxxx
in the upper-left corner of the screen.
for(y=0; y<10; y++) // outer loop,
drops down line-by-line
{
for(x=0; x<10; x++) // inner loop,
goes across char-by-char
cout << 'X'; // print 'X'
cout << endl; // go to new line
}
Of course, you can embed any kind of loop
inside any other kind of loop, and loops can
be nested in loops that are nested in other
loops, and so on.
Lecture No. 9
Simple Functions
/
What is a function?
Features of Function:
Declaring a Function:
void exforsys( );
Defining a function:
Declaring a function:
Function Definition:
return_datatype functionname(datatype1
variable1,datatype2 variable2,..)
{
Program statements
………….
return( variable);
}
In the above example, the return data type defines the
data type of the value returned by the function. The
arguments are passed inside the function name after
parentheses with the data type and the variable of each
argument. Care must be taken to mention the number of
arguments and the order of arguments in the same way as
in function declaration.
For example, if the function exforsys takes two integer
values x and y and adds them and returns the value z the
function definition would be defined as follows:
functionname(value1,value2,…);
exforsys(5,6);
#include
int exforsys(int,int);
void main()
{
int b;
int s=5,u=6;
b=exforsys(s,u);
cout<<”\n The Output is:”<
}
int exforsys(int x,int y)
{
int z;
z=x+y;
return(z);
}
The Output is:11
Lecture No. 10
Functions: Call by reference & Function return
Values
Passed By Value:
Passed By Reference:
#include <iostream.h>
int exforsys(int);
void main( )
{
int x;
cout << “\n Enter the Input Value: ”;
cin>>x;
//The exforsys(x) gets replaced with code return 5*x1;
cout<<”\n The Output is: “ << exforsys(x);
}
include <iostream.h>
int exforsys(int);
void main( )
{
int x;
cout << “\n Enter the Input Value: ”;
cin>>x;
//Call is made to the function exforsys
cout<<”\n The Output is: “ << exforsys(x);
}
Array Fundamentals
An array is a way to group together a number
of variables of a single data type. Arrays are
useful primarily because the individual
variables stored in an array can be accessed
using an index number. This makes it easy to
cycle through the array, accessing one
variable after another.
Defining an Array
To define an array, you tell the compiler to
set aside storage for a given number of data
items of a specified type. You also tell the
compiler the name of the array. Here’s an
example of an array definition that creates
storage for four integers. Give this array the
name age; perhaps it will be used to store the
ages of four people.
int age[4];
The int specifies the type of data to be
stored, age is the name of the array, and 4 is
the size of the array; that is, the maximum
number of variables of type int that it will
hold. Brackets [] (not braces or parentheses)
surround the size. It’s the brackets that tell
the compiler I’m defining an array and not
something else, such as a function. Figure 12-
1 shows the format of this array definition.
Array Elements
Multidimensional Arrays
Strings
Comparing Strings
Arrays of Strings
Figure 14-4
shows that there is some space wasted at the
ends of the shorter string constants because
all the string variables are the same length.
You can avoid this if you use pointers,
Variable names MAX and DPW are used for
the array dimensions and made them type
const. The entire array type has been made
const because presumably the days of the
week will never need to be changed.
Lecture No. 15
Structures
Specifying a Structure
Structure Usage
Specifying a Class
Introducing Constructors
Initialization
Creation
Destructors
No Return Value
What They Do
Constructor Arguments
A Two-Argument Constructor
A No-Argument Constructor
Copy Constructors
Copying Variables
Equivalent Syntax
Copying Objects
const Objects
Program Features
Let’s examine some important points demonstrated in
DESTRU.
External Variables
Passing by Value
Local Variables
The function func() creates a local variable, om4. The
first time it’s called, it creates Mike-6; the second time, it
creates Mike-8. These variables are destroyed as soon as
func() returns so, like the argument variable created by
the copy constructor, they don’t stay around very long.
Lecture No. 22
Static Data members and Member Functions
} ;
int shared::a; // define a
int main()
{
// initialize a before creating any
objects
shared::a = 99;
cout << "This is initial value of a: "
<< shared::a;
cout << "\n";
shared x;
cout << "This is x.a: " << x.a;
return 0;
}
Notice how a is referred to through the use of the class
name and the scope resolution
operator. In general, to refer to a static member
independently of an object, you must
qualify it by using the name of the class of which it is
amember.
One use of a static member variable is to provide access
control to some shared
resource used by all objects of a class. For example, you
might create several objects,
each of which needs to write to a specific disk file.
Clearly, however, only one object
can be allowed to write to the file at a time. In this case,
you will want to declare a
static variable that indicates when the file is in use and
when it is free. Each object then
interrogates this variable before writing to the file. The
following program shows how
you might use a static variable of this type to control
access to a scarce resource:
#include <iostream>
using namespace std;
class cl {
static int resource;
public:
int get_resource();
void free_resource() {resource = 0;}
};
int cl::resource; // define resource
int cl::get_resource()
{
if(resource) return 0; // resource
already in use
else {
resource = 1;
return 1; // resource allocated to
this object
}
}
int main()
{
cl ob1, ob2;
if(ob1.get_resource()) cout << "ob1
has resource\n";
if(!ob2.get_resource()) cout << "ob2
denied resource\n";
ob1.free_resource(); // let someone
else use it
if(ob2.get_resource())
cout << "ob2 can now use resource\n";
return 0;
}
Another interesting use of a static member variable is to
keep track of the number
of objects of a particular class type that are in existence.
For example,
#include <iostream>
using namespace std;
class Counter {
public:
static int count;
Counter() { count++; }
~Counter() { count--; }
};
int Counter::count;
void f();
int main(void)
{
Counter o1;
cout << "Objects in existence: ";
cout << Counter::count << "\n";
Counter o2;
cout << "Objects in existence: ";
cout << Counter::count << "\n";
f();
cout << "Objects in existence: ";
cout << Counter::count << "\n";
return 0;
}
void f()
{
Counter temp;
cout << "Objects in existence: ";
cout << Counter::count << "\n";
// temp is destroyed when f() returns
}
This program produces the following
output.
Objects in existence: 1
Objects in existence: 2
Objects in existence: 3
Objects in existence: 2
As you can see, the static member variable count is
incremented whenever an object is created and
decremented when an object is destroyed. This way, it
keeps track of how many objects of type Counter are
currently in existence.
By using static member variables, you should be able to
virtually eliminate any need for global variables. The
trouble with global variables relative to OOP is that they
almost always violate the principle of encapsulation.
Static Member Functions
Introduction to Inheritance
Rewriting Code
Function Libraries
To reduce the bugs introduced by modification of code,
programmers attempted to create self-sufficient program
elements in the form of functions. The hope was that
functions could be written that were general enough that
they could be used without modification in a variety of
programming situations. Software companies gathered
groups of such functions together into function libraries
and sold them to other programmers. Function libraries
were a step in the right direction, but, functions don’t
model the real world very well, because they don’t
include important data. All too often, functions require
modification to work in a new environment; it was
common for the purveyors of function libraries to provide
source code to make such modifications easier. But again,
the modifications introduced bugs.
Class Libraries
Inheritance Syntax
Class Hierarchy
Abstract Classes
Arguments
If you add an explicit one-argument constructor to the
derived class Mu, then you must also add a no-argument
constructor, just as you must with any class (assuming
you’re actually going to create objects with this
constructor). Listing 24-5 shows the previous program,
rewritten as CONSINH2, with these additional
constructors.
Listing 24-5 CONSINH2
// consinh2.cpp
// demonstrates constructors and
inheritance
class Mu
{
private:
int mudata; // data
public:
Mu() : mudata(0) // no-arg constructor
{ }
Mu(int m) : mudata(m) // one-arg
constructor
{ }
};
//////////////////////////////////////
//////////////////////////
class Nu : public Mu
{
public:
Nu() // no-arg constructor
{ }
Nu(int n) : Mu(n) // one-arg
constructor
{ }
};
//////////////////////////////////////
//////////////////////////
void main()
{
Nu n1; // calls no-arg constructor
Nu n2(77); // calls 1-arg constructor
}
In main(), the program successfully defines Nu objects
using both the no-argument and the one-argument
constructors. The one-argument constructor passes its
argument along to the constructor in Mu using a new
syntax: the initializer list.