Describe The Steps in Compiling and Executing A C++ Program With Programmatic Illustration
Describe The Steps in Compiling and Executing A C++ Program With Programmatic Illustration
Describe the steps in compiling and executing a C++ program with programmatic
illustration.
Ans.
There are three steps in executing a c++ program: Compiling, Linking and Running the program.
The c++ programs have to be typed in a compiler. All the programs discussed in the book will be
compiled on turbo c++ compiler. The turbo c++ compiler comes with an editor to type and edit
c++ program. After typing the program the file is saved with an extension .cpp. This is known as
source code. The source code has to be converted to an object code which is understandable by
the machine. This process is known as compiling the program. You can compile your program
by selecting compile from compile menu or press Alt+f9. After compiling a file with the same
name as source code file but with extension .obj. is created.
Second step is linking the program which creates an executable file .exe (filename same
as source code) after linking the object code and the library files (cs.lib) required for the
program. In a simple program, linking process may involve one object file and one library file.
However in a project, there may be several smaller programs. The object codes of these
programs and the library files are linked to create a single executable file. Third and the last
step is running the executable file where the statements in the program will be executed one
by one.
When you execute the program, the compiler displays the output of the program and
comes back to the program editor. To view the output and wait for user to press any key to
return to the editor, type getch() as the last statement in the program. Getch() is an inbuilt
predefined library function which inputs a character from the user through standard input.
However you should include another header file named conio.h to use this function. Conio.h
contains the necessary declarations for using this function. The include statement will be similar
to iostream.h.
During compilation, if there are any errors that will be listing by the compiler. The errors may
be any one of the following
1. Syntax error
This error occurs due to mistake in writing the syntax of a c++ statement or wrong use of
reserved words, improper variable names, using variables without declaration etc. Examples
are : missing semi colon or paranthesis, type integer for int datatype etc. Appropriate error
message and the statement number will be displayed. You can see the statement and make
correction to the program file, save and recompile it.
2. Logical error
This error occurs due to the flaw in the logic. This will not be identified by the compiler.
However it can be traced using the debug tool in the editor. First identify the variable which you
suspect creating the error and add them to watch list by selecting Debug ->Watches->Add
watch. Write the variable name in the watch expression. After adding all the variables required
to the watch list, go to the statement from where you want to observe. If you are not sure, you
can go to the first statement of the program. Then select Debug ->Toggle Breakpoint (or press
ctrl + f8). A red line will appear on the statement. Then Run the program by selecting Ctrl + f9 or
Run option from run menu. The execution will halt at the statement where you had added the
breakpoint. The watch variables and their values at that point of time will be displayed in the
bottom in the watch window. Press F8 to execute the next statement till you reach the end of
the program. In this way you can watch closely the values in the watch variables after execution
of each and every statement in the program. If you want to exit before execution of the last
statement press Ctrl + Break. To remove the breakpoint in the program go to the statement
where you have added breakpoint select Debug ->Toggle Breakpoint (or press ctrl + f8). Select
Debug -> watch ->remove watches to remove the variables in the watch list. This tool helps in
knowing the values taken by the variable at each and every step. You can compare the
expected value with the actual value to identify the error.
3. Linker error
This error occur when the files during linking are missing or mispelt
4. Runtime error
This error occurs if the programs encounters division by zero, accessing a null pointer etc during
execution of the program
2. Describe the theory with programming examples the selection control statements in
C++.
Ans.
If statement
The expression or condition is any expression built using relational operators which
either yields true or false condition. If no relational operators are used for comparison, then the
expression will be evaluated and zero is taken as false and non zero value is taken as true. If the
condition is true, statement1 and statement2 is executed otherwise statement 3 and statement
4 is executed. Else part in the if statement is optional. If there is no else part, then the next
statement after the if statement is exceuted, if the condition is false. If there is only one
statement to be executed in the if part or in the else part, braces can be omitted.
// evenodd.cpp
# include <iostream.h>
# include <conio.h>
void main()
{
int num;
cout<<”Please enter a number”<<endl;
cin>>num;
if ((num%2) == 0)
cout<<num <<” is a even number”;
else
cout<<num <<” is a odd number”;
getch();
}
The above program accepts a number from the user and divides it by 2 and if the
remainder (remainder is obtained by modulus operator) is zero, it displays the number is even,
otherwise as odd. We make use of the relational operator == to compare whether remainder is
equal to zero or not.
Nested If statement
If (condition1)
{ if (condition 2)
{ statement1;
Statement2;
}
else if (condition3)
{statement3;
}
}
else statement4;
In the above example statement1 will be executed if both the condition1 and condition2 are
true and in all other cases statement2 will be executed.
If ((condition1 || (condition2))
statement1;
else
statement2;
In the above example statement1 will be executed if either condition1 or condition2 are
true and even if both are true. Statement2 will be executed if both the conditions are false. The
following program demonstrates the use of && operator and nested if statement.
//Large.cpp
# include <iostream.h>
void main()
{ int a,b,c;
cout<<”Please enter three numbers”;
cin>>a>>b>>c;
if ((a>b) && (b>c))
cout<<a<< “ is the largest number”;
else if ((b>a) && (b>c))
cout<<b<< “ is the largest number”;
else if ((c>a) && (c>b))
cout<<c<< “ is the largest number”;
}
The above program accepts three numbers from the user and displays which is the
largest number among the three.( assumption is that all the numbers are unique, the program
has to be modified if you would like to allow same number twice)
B) switch statements
Ans –
Switch statement
Nested ifs can be confusing if the if statement is deeply nested. One alternative to
nested if is the switch statement which can be used to increase clarity in case of checking the
different values of the same variable and execute statements accordingly.
Syntax :
Switch (variablename)
{ case value1: statement1;
break;
case value2: statement2;
break;
case value3: statement3;
break;
default: statement4;
}
If the variable in the switch statement is equal to value1 then statement1 is executed, if
it is equal to value2 then statement2 is executed, if it is value3 then statement3 is executed. If
the variable value is not in any of the cases listed then the default case statement or
statement4 is executed. The default case specification is optional, however keeping it is a good
practice. It can also be used for displaying any error message. Each case can have any number
of statements. However every case should have a break statement as the last statement. Break
statement takes the control out of the switch statement. The absence of the break statement
can cause execution of statements in the next case. No break is necessary for the last case. In
the above example, default case does not contain a break statement.
position.cpp
# include<iostream.h>
void main()
{ char pos;
int x=15, y=15;
cout << “ you are currently located at” <<x<<” “<<y<<endl;
cout>>”please choose the letter to move l for left, r for right, u for up and d for down” <<endl;
cin>>pos;
switch (pos)
{ case ‘l’: x–;
break;
case ‘r’: x++;
break;
case ‘u’: y++;
break;
case ‘d’: y–;
break;
default: cout<<”You selected a wrong option”;
}
cout<<“ you are now located at” <<x<<” “<<y;
}
The above program asks the user to enter l,r,u,d for allowing him to move left,right,up
and down respectively. The position is initialised to 15 and 15 which are x and y coordinates of
his position. Depending upon the what user has selected the the x and y co-ordinates are
incremented or decremented by one(x++ is same as x=x+1). If the user types a letter other than
l,r,u,d, he gets an error message. Since the switch variable is a character, l,u,r,d and enclosed
within single quote.
++ and — operator can be used as postfix or as prefix operator which has no effect if
used as an independent statement. However if it used as part of an expression, the prefix
operator will be operated and then the expression will be evaluated whereas the postfix
operated will be evaluated later.
For example in the statement x= a+ (b++), a will be added to b and then stored in x and
then the value of b will be incremented. If the same expression is written as x=a+(++b), the the
b will be incremented and then added to a and stored in x.
for(i=0;i<3;i++)
{
flag=1;
sp=a[i][0],pos=0;
for(j=1;j<3;j++)
{
if(a[i][j]<sp)
{ sp=a[i][j];
pos=j;
}
}
for(k=0;k<3;k++)
{
if(a[k][pos]<sp)
{
flag=0;
break;
}
}
if(flag==1)
cout<<"The saddle point of row "<<i+1<<" is "<<sp<<endl;
}
getch();
}
4. Describe and Demonstrate the concept of Pass by Value and Pass By Reference using
appropriate programming examples of your own.
Ans.
Pass by Value
Consider a pair of C++ functions defined in Program. The function One calls the function Two. In
general, every function call includes a (possibly empty) list of arguments. The arguments
specified in a function call are called actual parameters . In this case, there is only one actual
parameter y.
void Two(int x)
{
x=2;
cout << r << endl;
}
void One()
{
int y=1;
Two(y);
cout << y << endl;
}
Program: Example of Pass-By-Value Parameter Passing
The method by which the parameter is passed to a function is determined by the function
definition. In this case, the function Two is defined as accepting a single argument of type int
called x. The arguments which appear in a function definition are called formal parameters . If
the type of a formal parameter is not a reference , then the parameter passing method is pass-
by-value.
The semantics of pass-by-value work like this: The effect of the formal parameter definition is to
create a local variable of the specified type in the given function. E.g., the function Two has a
local variable of type int called x. When the function is called, the values (r-values) of the actual
parameters are used to initialize the formal parameters before the body of the function is
executed.
Since the formal parameters give rise to local variables, if a new value is assigned to a formal
parameter, that value has no effect on the actual parameters. Therefore, the output obtained
produced by the function One defined in Program is:
2
1
Pass by Reference
Consider the pair of C++ functions defined in Program . The only difference between this code
and the code given in Program is the definition of the formal parameter of the function Two: In
this case, the parameter x is declared to be a reference to an int. In general, if the type of a
formal parameter is a reference, then the parameter passing method is pass-by-reference .
void Two(int& x)
{
x=2;
cout << r << endl;
}
void One()
{
int y=1;
Two(y);
cout << y << endl;
}
Program: Example of Pass-By-Reference Parameter Passing
A reference formal parameter is not a variable. When a function is called that has a reference
formal parameter, the effect of the call is to associate the reference with the corresponding
actual parameter. I.e., the reference becomes an alternative name for the corresponding actual
parameter. Consequently, this means that the actual parameter passed by reference must be
variable.
A reference formal parameter can be used in the called function everywhere that a variable can
be used. In particular, if the reference formal parameter is used where a r-value is required, it is
the r-value of actual parameter that is obtained. Similarly, if the reference parameter is used
where an l-value is required, it is the l-value of actual parameter that is obtained. Therefore, the
output obtained produced by the function one defined in Program is:
2
2
Derivation
Inheritance is implemented in C++ through the mechanism of derivation. Derivation allows you
to derive a class, called a derived class, from another class, called a base class.
Derived class syntax
In the declaration of a derived class, you list the base classes of the derived class. The derived
class inherits its members from these base classes.
The qualified_class_specifier must be a class that has been previously declared in a class
declaration.
The following example shows the declaration of the derived class D and the base classes V, B1,
and B2. The class B1 is both a base class and a derived class because it is derived from class V
and is a base class for D:
class V { /* ... */ };
class B1 : virtual public V { /* ... */ };
class B2 { /* ... */ };
Classes that are declared but not defined are not allowed in base lists.
For example:
class X;
// error
class Y: public X { };
The compiler will not allow the declaration of class Y because X has not been defined.
When you derive a class, the derived class inherits class members of the base class. You can
refer to inherited members (base class members) as if they were members of the derived class.
For example:
class Base {
public:
int a,b;
};
class Derived : public Base {
public:
int c;
};
int main() {
Derived d;
d.a = 1; // Base::a
d.b = 2; // Base::b
d.c = 3; // Derived::c
}
The derived class can also add new class members and redefine existing base class members. In
the above example, the two inherited members, a and b, of the derived class d, in addition to
the derived class member c, are assigned values. If you redefine base class members in the
derived class, you can still refer to the base class members by using the :: (scope resolution)
operator. For example:
#include <iostream>
using namespace std;
class Base {
public:
char* name;
void display() {
cout << name << endl;
}
};
// call Derived::display()
d.display();
// call Base::display()
d.Base::display();
}
You can manipulate a derived class object as if it were a base class object. You can use a pointer
or a reference to a derived class object in place of a pointer or reference to its base class. For
example, you can pass a pointer or reference to a derived class object D to a function expecting
a pointer or reference to the base class of D. You do not need to use an explicit cast to achieve
this; a standard conversion is performed. You can implicitly convert a pointer to a derived class
to point to an accessible unambiguous base class. You can also implicitly convert a reference to
a derived class to a reference to a base class.
The following example demonstrates a standard conversion from a pointer to a derived class to
a pointer to a base class:
#include <iostream>
using namespace std;
class Base {
public:
char* name;
void display() {
cout << name << endl;
}
};
int main() {
Derived d;
d.name = "Derived Class";
d.Base::name = "Base Class";
// call Base::display()
bptr->display();
Base Class
The statement Base* bptr = dptr converts a pointer of type Derived to a pointer of type Base.
The reverse case is not allowed. You cannot implicitly convert a pointer or a reference to a base
class object to a pointer or reference to a derived class. For example, the compiler will not allow
the following code if the classes Base and Class are defined as in the above example:
int main() {
Base b;
b.name = "Base class";
The compiler will not allow the statement Derived* dptr = &b because the statement is trying
to implicitly convert a pointer of type Base to a pointer of type Derived.
If a member of a derived class and a member of a base class have the same name, the base
class member is hidden in the derived class. If a member of a derived class has the same name
as a base class, the base class name is hidden in the derived class.
Inheritance
Inheritance is a mechanism of reusing and extending existing classes without modifying them,
thus producing hierarchical relationships between them.
Inheritance is almost like embedding an object into a class. Suppose that you declare an object
x of class A in the class definition of B. As a result, class B will have access to all the public data
members and member functions of class A. However, in class B, you have to access the data
members and member functions of class A through object x. The following example
demonstrates this:
#include <iostream>
using namespace std;
class A {
int data;
public:
void f(int arg) { data = arg; }
int g() { return data; }
};
class B {
public:
A x;
};
int main() {
B obj;
obj.x.f(20);
cout << obj.x.g() << endl;
// cout << obj.g() << endl;
}
In the main function, object obj accesses function A::f() through its data member B::x with the
statement obj.x.f(20). Object obj accesses A::g() in a similar manner with the statement
obj.x.g(). The compiler would not allow the statement obj.g() because g() is a member function
of class A, not class B.
The inheritance mechanism lets you use a statement like obj.g() in the above example. In order
for that statement to be legal, g() must be a member function of class B.
Inheritance lets you include the names and definitions of another class's members as part of a
new class. The class whose members you want to include in your new class is called a base
class. Your new class is derived from the base class. The new class contains a sub object of the
type of the base class. The following example is the same as the previous example except it
uses the inheritance mechanism to give class B access to the members of class A:
#include <iostream>
using namespace std;
class A {
int data;
public:
void f(int arg) { data = arg; }
int g() { return data; }
};
class B : public A { };
int main() {
B obj;
obj.f(20);
cout << obj.g() << endl;
}
Class A is a base class of class B. The names and definitions of the members of class A are
included in the definition of class B; class B inherits the members of class A. Class B is derived
from class A. Class B contains a subobject of type A.
You can also add new data members and member functions to the derived class. You can
modify the implementation of existing member functions or data by overriding base class
member functions or data in the newly derived class.
You may derive classes from other derived classes, thereby creating another level of
inheritance. The following example demonstrates this:
struct A { };
struct B : A { };
struct C : B { };
Class B is a derived class of A, but is also a base class of C. The number of levels of inheritance is
only limited by resources.
Multiple inheritance allows you to create a derived class that inherits properties from more
than one base class. Because a derived class inherits members from all its base classes,
ambiguities can result. For example, if two base classes have a member with the same name,
the derived class cannot implicitly differentiate between the two members. Note that, when
you are using multiple inheritance, the access to names of base classes may be ambiguous.
A direct base class is a base class that appears directly as a base specifier in the declaration of
its derived class.
An indirect base class is a base class that does not appear directly in the declaration of the
derived class but is available to the derived class through one of its base classes. For a given
class, all base classes that are not direct base classes are indirect base classes. The following
example demonstrates direct and indirect base classes:
class A {
public:
int x;
};
class B : public A {
public:
int y;
};
class C : public B { };
Class B is a direct base class of C. Class A is a direct base class of B. Class A is an indirect base
class of C. (Class C has x and y as its data members.)
Polymorphic functions are functions that can be applied to objects of more than one type. In C+
+, polymorphic functions are implemented in two ways:
6. Describe the Friend functions and friend classes with programming examples.
Ans
Friend function
When a data is declared as private inside a class, then it is not accessible from outside the class.
A function that is not a member or an external class will not be able to access the private data.
A programmer may have a situation where he or she would need to access private data from
non-member functions and external classes. For handling such cases, the concept of Friend
functions is a useful tool.
A friend function is used for accessing the non-public members of a class. A class can allow non-
member functions and other classes to access its own private data, by making them friends.
Thus, a friend function is an ordinary function or a member of another class.
The friend function is written as any other normal function, except the function declaration of
these functions is preceded with the keyword friend. The friend function must have the class to
which it is declared as friend passed to it in argument.
The keyword friend is placed only in the function declaration of the friend function and not in
the function definition.
When a class is declared as a friend, the friend class has access to the private data of the class
that made this a friend.
A friend function, even though it is not a member function, would have the rights to access the
private members of the class.
The function can be invoked without the use of an object. The friend function has its argument
as objects, seen in example below.
#include
class exforsys
{
private:
int a,b;
public:
void test()
{
a=100;
b=200;
}
friend int compute(exforsys e1)
//Friend Function Declaration with keyword friend and with the object of class exforsys to
which it is friend passed to it
};
The function compute() is a non-member function of the class exforsys. In order to make this
function have access to the private data a and b of class exforsys , it is created as a friend
function for the class exforsys. As a first step, the function compute() is declared as friend in the
class exforsys as:
Friend Class
C++ provides the friend keyword to do just this. Inside a class, you can indicate that other
classes (or simply functions) will have direct access to protected and private members of the
class. When granting access to a class, you must specify that the access is granted for a class
using the class keyword:
friend class aClass;
Note that friend declarations can go in either the public, private, or protected section of a
class--it doesn't matter where they appear. In particular, specifying a friend in the section
marked protected doesn't prevent the friend from also accessing private fields. Here is a more
concrete example of declaring a friend:
class Node
{
private:
int data;
int key;
// ...
friend class BinaryTree; // class BinaryTree can now access data directly
};
Now, Node does not need to provide any means of accessing the data stored in the tree. The
BinaryTree class that will use the data is the only class that will ever need access to the data or
key. (The BinaryTree class needs to use the key to order the tree, and it will be the gateway
through which other classes can access data stored in any particular node.) Now in the
BinaryTree class, you can treat the key and data fields as though they were public:
class BinaryTree
{
private:
Node *root;
Ans.
So far we have seen just one way to open a file, either for reading, either for writing. But
it can be opened another way too. So far, you should be aware of this method:
ifstream OpenFile(“cpp-home.txt”);
Well, this is not the only way. As mentioned before, the above code creates an object
from class ifstream, and passes the name of the file to be opened to its constructor. But in fact,
there are several overloaded constructors, which can take more than one parameter. Also,
there is function open() that can do the same job. Here is an example of the above code, but
using the open() function:
ifstream OpenFile;
OpenFile.open(“cpp-home.txt”);
Other use of open() is for example if you open a file, then close it, and using the same
file handle open another file. This way, you will need the open() function.
#include <fstream.h>
void read(ifstream &T) { //pass the file stream to the function
//the method to read a file
char ch;
while(!T.eof()) {
T.get(ch);
cout << ch;
}
cout << endl << "——–" << endl;
}
void main() {
ifstream T("file1.txt");
read(T);
T.close();
T.open("file2.txt");
read(T);
T.close();
}
So, as long as file1.txt and file2.txt exists and has some text into, you will see it.
You should know that filename is the name of the file (a string). What is new here is the
open_mode. The value of open_mode defines how to a file can be opened. Here is a table of the
open modes:
All these values are int constants from an enumerated type. But for making your life
easier, you can use them as you see them in the table. Here is an example on how to use the
open modes:
#include <fstream.h>
void main() {
ofstream SaveFile("file1.txt", ios::ate);
SaveFile << "That’s new!n";
SaveFile.close();
}
As you see in the table, using ios::ate will write at the end of the file. If it wasn’t used,
the file would have been overwritten. So, if file1.txt has this text:
Running the above code, will add “That’s new!” to it, so it will look this way:
If you want to set more than one open mode, just use the OR operator (|). This way:
ios::ate | ios::binary
Using different open modes helps make file handling an easy job. Having
the liberty to choose a combination of these, in a sane way, comes in very handy in using
streams effectively, and to the requirements of the project.
Moving on to something more intriguing and important; we can create a file stream handle,
which you can use to read/write file, in the same time. Here is how it works:
In fact, that is only the declaration. The code line above creates a file stream handle,
named File. As you know, this is an object from class fstream. When using fstream, you should
specify ios::in and ios::out as open modes. This way, you can read from the file, and write in it,
in the same time, without creating new file handles. Well, of course, you can only read or write.
Here is the code example:
#include <fstream.h>
void main() {
fstream File("test.txt", ios::in | ios::out);
File << "Hi!"; //put “Hi!” in the file
static char str[10]; //when using static, the array is automatically
//initialized, and very cell NULLed
File.seekg(ios::beg); //get back to the beginning of the file
//this function is explained a bit later
File >> str;
cout << str << endl;
File.close();
}
This line, creates an object from class fstream. At the time of execution, the program opens the
file test.txt in read/write mode. This means, that you can read from the file, and put data into
it, at the same time.
I am sure the reader is aware of this and hence the explanation for this statement is redundant.
This makes a char array with 10 cells. The word static initializes the array when at the time of
creation.
File.seekg(ios::beg);
To understand this statement, let us go back and recollect some basics. We have seen this
before:
while(!OpenFile.eof()) {
OpenFile.get(ch);
cout << ch;
}
This is a while loop, that will loop until you reach the end of the file. But how does the
loop know if the end of the file is reached? The answer is; when you read the file, there is
something like an inside-pointer (current reading/writing position) that shows where you are
up to, with the reading (and writing, too). Every time you call OpenFile.get(ch) it returns the
current character to the ch variable, and moves the inside-pointer one character after that, so
that the next time this function is called, it will return the next character. And this repeats, until
you reach the end of the file.
Going back to the code line; the function seekg() will put the inside-pointer to a specific place
(specified by you). One can use:
Or you can also set the number of characters to go back or after. For example, if you want to go
5 characters back, you should write:
File.seekg(-5);
File.seekg(40);
It is imperative to mention that the seekg() function is overloaded, and it can take two
parameters, too. The other version is this one:
File.seekg(-5, ios::end);
In this example, you will be able to read the last 4 characters of the text, because:
Why you will read 4 but not 5 characters? One character is lost, because the last thing in the file
is neither a character nor white space. It is just position (i.e., end of file).
Why this function was used the program above. After putting “Hi!” in the file, the inside-pointer
was set after it, i.e., at the end of the file. And as we want to read the file, there is nothing that
can be read at the end. Hence, we have to put the inside-pointer at the beginning. And that is
exactly what this function does.
I believe this line reminds us of cin >>. In fact, it has much to do with it. This line reads one word
from the file, and puts it into the specified array. For example, if the file has this text:
8. Explain the concept of class templates in C++ with some real time programming examples.
Ans.
A class template definition looks like a regular class definition, except it is prefixed by the
keyword template. For example, here is the definition of a class template for a Stack.
template <class T>
class Stack {
public:
Stack(int = 10);
~Stack() { delete [] stackPtr ; }
int push(const T&);
int pop(T&);
int isEmpty()const { return top == -1; }
int isFull() const { return top == size – 1; }
private:
int size; // number of elements on Stack.
int top;
T* stackPtr;
};
T is a type parameter and it can be any type. For example, Stack<Token>, where Token
is a user defined class. T does not have to be a class type as implied by the keyword class. For
example, Stack<int> and Stack<Message*> are valid instantiations, even though int and
Message* are not "classes".
When compiling B.cpp, the compiler has both the declarations and the definitions
available. At this point the compiler does not need to generate any definitions for template
classes, since there are no instantiations. When the compiler compiles main.cpp, there are two
instantiations: template class B<int> and B<float>. At this point the compiler has the
declarations but no definitions.
While implementing class template member functions, the definitions are prefixed by
the keyword template. Here is the complete implementation of class template Stack:
//stack.h
#pragma once
template <class T>
class Stack {
public:
Stack(int = 10);
~Stack() { delete [] stackPtr; }
int push(const T&);
int pop(T&); // pop an element off the stack
int isEmpty()const { return top == -1; }
int isFull() const { return top == size – 1; }
private:
int size; // Number of elements on Stack
int top;
T* stackPtr;
};
//constructor with the default size 10
template <class T>
Stack<T>::Stack(int s) {
size = s > 0 && s < 1000 ? s : 10;
top = -1; // initialize stack
stackPtr = new T[size];
}
// push an element onto the Stack
template <class T>
int Stack<T>::push(const T& item) {
if (!isFull())
{
stackPtr[++top] = item;
return 1; // push successful
}
return 0; // push unsuccessful
}
// pop an element off the Stack
template <class T>
int Stack<T>::pop(T& popValue) {
if (!isEmpty())
{
popValue = stackPtr[top--];
return 1; // pop successful
}
return 0; // pop unsuccessful
}
Using a class template is easy. Create the required classes by plugging in the actual type
for the type parameters. This process is commonly known as "Instantiating a class". Here is a
sample driver class that uses the Stack class template.
#include <iostream>
#include "stack.h"
using namespace std;
void main() {
typedef Stack<float> FloatStack;
typedef Stack<int> IntStack;
FloatStack fs(5);
float f = 1.1;
cout << "Pushing elements onto fs" << endl;
while (fs.push(f))
{
cout << f << ‘ ‘;
f += 1.1;
}
cout << endl << "Stack Full." << endl
<< endl << "Popping elements from fs" << endl;
while (fs.pop(f))
cout << f << ‘ ‘;
cout << endl << "Stack Empty" << endl;
cout << endl;
IntStack is;
int i = 1.1;
cout << "Pushing elements onto is" << endl;
while (is.push(i))
{
cout << i << ‘ ‘;
i += 1;
}
cout << endl << "Stack Full" << endl
<< endl << "Popping elements from is" << endl;
while (is.pop(i))
cout << i << ‘ ‘;
cout << endl << "Stack Empty" << endl;
}
Output:
Stack Empty
In the above example we defined a class template Stack. In the driver program we
instantiated a Stack of float (FloatStack) and a Stack of int(IntStack). Once the template classes
are instantiated you can instantiate objects of that type (for example, fs and is.)
· If the template definition changes, simply change the typedef definition. For example,
currently the definition of template class vector requires a second parameter.
Assignment Set – 2
Ans.
Constructor
The main use of constructors is to initialize objects. The function of initialization is automatically
carried out by the use of a special member function called a constructor.
Constructor is a special member function that takes the same name as the class name. The
syntax generally is as given below:
X::X()
In the above example the arguments is optional.
There are several forms in which a constructor can take its shape namely:
Default Constructor:
This constructor has no arguments in it. Default Constructor is also called as no argument
constructor.
For example:
class Exforsys
{
private:
int a,b;
public:
Exforsys();
...
};
Exforsys :: Exforsys()
{
a=0;
b=0;
}
Copy constructor:
This constructor takes one argument. Also called one argument constructor. The main use of
copy constructor is to initialize the objects while in creation, also used to copy an object. The
copy constructor allows the programmer to create a new object from an existing one by
initialization.
Exforsys e3(e2);
or
Exforsys e3=e2;
Both the above formats can be sued to invoke a copy constructor.
For Example:
#include <iostream.h>
class Exforsys()
{
private:
int a;
public:
Exforsys()
{}
Exforsys(int w)
{
a=w;
}
Exforsys(Exforsys& e)
{
a=e.a;
cout<<” Example of Copy Constructor”;
}
void result()
{
cout<< a;
}
};
void main()
{
Exforsys e1(50);
Exforsys e3(e1);
cout<< “\ne3=”;e3.result();
}
In the above the copy constructor takes one argument an object of type Exforsys which is
passed by reference. The output of the above program is
The constructor must be defined in the public. The constructor must be a public member.
Overloading of constructors is possible. This will be explained in later sections of this tutorial.
Destructors
Destructors are also special member functions used in C++ programming language. Destructors
have the opposite function of a constructor. The main use of destructors is to release dynamic
allocated memory. Destructors are used to free memory, release resources and to perform
other clean up. Destructors are automatically named when an object is destroyed. Like
constructors, destructors also take the same name as that of the class name.
Syntax
~ classname();
The above is the general syntax of a destructor. In the above, the symbol tilda ~ represents a
destructor which precedes the name of the class.
Like the constructor, the destructor must also be defined in the public. The destructor must be
a public member.
The Destructor does not take any argument which means that destructors cannot be
overloaded.
class Exforsys
{
private:
……………
public:
Exforsys()
{}
~ Exforsys()
{}
}
A. Types of Inheritance
Single Inheritance
In "single inheritance," a common form of inheritance, classes have only one base class.
class CFather
{
public:
void Gender () {cout<<"Male" ;}
void Blood () {cout<<"Red";}
void Initial (){cout<<"Angajala";}
void Address (){cout <<"******" ;}
};
Class CDerived:public CBase
{
};
Multilevel Inheritance
It is the enhancement of the concept of inheritance. When a subclass is derived from a derived
class then this mechanism is known as the multilevel inheritance. The derived class is called the
subclass or child class for its parent class and this parent class works as the child class for it's
just above (parent) class. Multilevel inheritance can go up to any number of levels.
The best example is Say we have 3 classes
ClassA, ClassB and ClassC. ClassB is derived from ClassA and ClassC is derived ClassB
This is multi level inheritance..
ClassA
^
|
ClassB
^
|
ClassC
. class CFather
{
public:
void Gender () {cout<<"Male" ;}
void Blood () {cout<<"Red";}
void Initial (){cout<<"Angajala";}
void Address (){cout <<"******" ;}
};
Class CDerived:public CBase
{
};
Class C2Derived:public CDerived
{
};
Multiple Inheritances
You can derive a class from any number of base classes. Deriving a class from more than one
direct base class is called multiple inheritances.
In the following example, classes A, B, and C are direct base classes for the derived class X:
class A { /* ... */ };
class B { /* ... */ };
class C { /* ... */ };
class X : public A, private B, public C { /* ... */ };
Hierarchical Inheritance
It is a type of inheritance where one or more derived classes is derived from common( or one )
base class
E.g.
class A
{
// definition of class A
};
class B : public A //derived from A
{
// definition of class B
};
class C : public A //derived from A
{
// definition of class c
};
Hybrid Inheritance
In this type of inheritance, we can have mixture of number of inheritances but this can generate
an error of using same name function from no of classes, which will bother the compiler to how
to use the functions. Therefore, it will generate errors in the program. This has known as
ambiguity or duplicity.
Let's say that we are writing a text-based medieval video game. Our video game will have two
types of characters: the players and the monsters. A player has to know the values of certain
attributes: health, strength, and agility. A player must also know what type of weapon and what
type of armor they possess. A player must be able to move through a maze, attack a monster,
and pick up treasure. So, to design this "player object", we must first separate data that the
player object must know from actions that the player must know how to execute. The definition
for a player object could be:
Player Object:
data:
health
strength
agility
type of weapon
type of armor
actions:
move
attack monster
get treasure
END;
Data that an object keeps track of is called member data and actions that an object knows how
to do are called member functions. Member data is very similar to variables in a regular
function in the sense that no other object can get access to that data (unless given permission
by the object). Member data keeps its values over the life of an object
There is a very important distinction between an object and an instance of an object. An object
is actually a definition, or a template for instances of that object. An instance of an object is an
actual thing that can be manipulated. For instance, we could define a Person object, which may
include such member data as hair color, eye color, height, weight, etc. An instance of this object
could be "Dave" and Dave has values for hair color, eye color, etc. This allows for multiple
instances of an object to be created. Let's go back to the medieval video game example and
define the monster object.
Some piece of your program can either possess an instance of an object, or know where an
instance of an object is. An instance of an object is a chunk of memory that is big enough to
store all the member data of that object. A pointer is an address that explains how to get to
where the instance is actually held in memory. Here's a quick example:
Our Player object has three pieces of data that it owns: strength, agility, and health. These are a
part of the player object. That makes sense in real world terms. The player knows about two
other pieces of data: the weapon and the armor that the player possesses. Here's a diagram for
an instance of the player object.
So that is how to conceptually think of pointers. Now what's really going on? Memory in a
computer is a complicated thing, but let's reduce it to it's simplest form: one large string of slots
with addresses that data can be put in. As in the following picture:
If we were to access the spot in memory with address 3, we would get the value 45. If we were
to access the spot in memory with address 2 we would get the value "Dave". The previous
diagram over simplifies two important concepts, however
3. Describe the theory behind Virtual Functions and Polymorphism along with suitable
programming examples for each.
Virtual, as the name implies, is something that exists in effect but not in reality. The concept of
virtual function is the same as a function, but it does not really exist although it appears in
needed places in a program. The object-oriented programming language C++ implements the
concept of virtual function as a simple member function, like all member functions of the class.
The functionality of virtual functions can be over-ridden in its derived classes. The programmer
must pay attention not to confuse this concept with function overloading. Function overloading
is a different concept and will be explained in later sections of this tutorial. Virtual function is a
mechanism to implement the concept of polymorphism (the ability to give different meanings
to one function).
The vital reason for having a virtual function is to implement a different functionality in the
derived class.
Properties of Virtual Functions:
Virtual Functions are resolved during run-time or dynamic binding. Virtual functions are also
simple member functions. The main difference between a non-virtual C++ member function
and a virtual member function is in the way they are both resolved. A non-virtual C++ member
function is resolved during compile time or static binding. Virtual Functions are resolved during
run-time or dynamic binding
Virtual functions are member functions declared with the keyword virtual.
class classname //This denotes the base class of C++ virtual function
{
public:
virtual void memberfunctionname() //This denotes the C++ virtual function
{
.............
............
}
};
Eg.
class BaseClass{
public:
virtual void who(void)
{
cout << "Base\n";
}
};
class Derived1 : public BaseClass
{
public:
void who (void)
{
cout << "Derived Class 1 \n";
}
};
int main(void)
{
BaseClass b;
BaseClass *bp;
Derived1 d1;
Derived2 d2;
bp = &b;
bp ->who(); //Executes the base class who function
bp = &d1;
bp ->who(); //Executes the Derived1 class who function
bp = &d2;
bp ->who(); //Executes the Derived2 class who function
}
//Out put
//Base
//Derived Class 1
//Derived Class 2
6 + 10
The above refers to integer addition.
The same + operator can be used with different meanings with strings:
"Exforsys" + "Training"
The same + operator can also be used for floating point addition:
7.15 + 3.78
Polymorphism is a powerful feature of the object oriented programming language C++. A single
operator + behaves differently in different contexts such as integer, float or strings referring the
concept of polymorphism. The above concept leads to operator overloading. The concept of
overloading is also a branch of polymorphism. When the exiting operator or function operates
on new data type it is overloaded. This feature of polymorphism leads to the concept of virtual
methods.
Polymorphism refers to the ability to call different functions by using only one type of function
call. Suppose a programmer wants to code vehicles of different shapes such as circles, squares,
rectangles, etc. One way to define each of these classes is to have a member function for each
that makes vehicles of each shape. Another convenient approach the programmer can take is
to define a base class named Shape and then create an instance of that class. The programmer
can have array that hold pointers to all different objects of the vehicle followed by a simple
loop structure to make the vehicle, as per the shape desired, by inserting pointers into the
defined array. This approach leads to different functions executed by the same function call.
Polymorphism is used to give different meanings to the same concept. This is the basis for
Virtual function implementation.
In polymorphism, a single function or an operator functioning in many ways depends upon the
usage to function properly. In order for this to occur, the following conditions must apply:
All different classes must be derived from a single base class. In the above example, the shapes
of vehicles (circle, triangle, rectangle) are from the single base class called Shape.
The member function must be declared virtual in the base class. In the above example, the
member function for making the vehicle should be made as virtual to the base class.
Types of Polymorphism:
C++ provides three different types of polymorphism.
•Virtual functions
•Function name overloading
•Operator overloading
In addition to the above three types of polymorphism, there exist other kinds of polymorphism:
•run-time
•compile-time
•ad-hoc polymorphism
•parametric polymorphism
4. Write a program in C++ for copying and printing the contents of files.
Ans.
#include<iostream.h>
#include<fstream.h>
#include<conio.h>
#include<stdio.h>
#include<process.h>
#include<string.h>
struct student
{ int rollno;
char name[20];
int marks;
}s;
void main()
{ ifstream fin;
ofstream fout;
int ch,no;
do
{ clrscr();
cout<<"\nMenu\n";
cout<<"\n1. Add";
cout<<"\n2. Search";
cout<<"\n3. Display";
cout<<"\n4. Exit";
cout<<"\n\nEnter your choice: ";cin>>ch;
switch(ch)
{ case 1:
{ cout<<"\nEnter rollno. :";cin>>s.rollno;
cout<<"\nName: ";gets(s.name);
cout<<"\nMarks: ";cin>>s.marks;
fout.open("student.dat",ios::binary|ios::app);
fout.write((char*)&s,sizeof(student));
fout.close();
break;
}
case 2:
{ cout<<"\nEnter rollno. to be searched: ";cin>>no;
fin.open("student.dat",ios::binary|ios::in);
while(!fin.eof())
{ fin.read((char*)&s,sizeof(student));
if (s.rollno==no)
{ cout<<"\nRollno: "<<s.rollno;
cout<<"\nName: "<<s.name;
cout<<"\nMarks: "<<s.marks;
getch();
break;
}
}
fin.close();
break;
}
case 3:
{ fin.open("student.dat",ios::binary|ios::in);
while(!fin.eof())
{ clrscr();
fin.read((char*)&s,sizeof(student));
cout<<"\nRoll No. :"<<s.rollno;
cout<<"\nName: "<<s.name;
cout<<"\nMarks: "<<s.marks;
getch();
}
fin.close(); break;
}
case 4:exit(0);
} while (ch<=4);
}
5. Explain Class templates and function templates.
Ans.
Many C++ programs use common data structures like stacks, queues and lists. A program may
require a queue of customers and a queue of messages. One could easily implement a queue of
customers, then take the existing code and implement a queue of messages. The program
grows, and now there is a need for a queue of orders. So just take the queue of messages and
convert that to a queue of orders (Copy, paste, find, replace????). Need to make some changes
to the queue implementation? Not a very easy task, since the code has been duplicated in
many places. Re-inventing source code is not an intelligent approach in an object oriented
environment which encourages re-usability. It seems to make more sense to implement a
queue that can contain any arbitrary type rather than duplicating code. How does one do that?
The answer is to use type parameterization, more commonly referred to as templates.
C++ templates allow one to implement a generic Queue<T> template that has a type parameter
T. T can be replaced with actual types, for example, Queue<Customers>, and C++ will generate
the class Queue<Customers>. Changing the implementation of the Queue becomes relatively
simple. Once the changes are implemented in the template Queue<T>, they are immediately
reflected in the classes Queue<Customers>, Queue<Messages>, and Queue<Orders>.
Templates are very useful when implementing generic constructs like vectors, stacks, lists,
queues which can be used with any arbitrary type. C++ templates provide a way to re-use
source code as opposed to inheritance and composition which provide a way to re-use object
code.
C++ provides two kinds of templates: class templates and function templates. Use function
templates to write generic functions that can be used with arbitrary types. For example, one
can write searching and sorting routines which can be used with any arbitrary type. The
Standard Template Library generic algorithms have been implemented as function templates,
and the containers have been implemented as class templates.
Class Templates
A class template definition looks like a regular class definition, except it is prefixed by the
keyword template. For example, here is the definition of a class template for a Stack.
T is a type parameter and it can be any type. For example, Stack<Token>, where Token is a user
defined class. T does not have to be a class type as implied by the keyword class. For example,
Stack<int> and Stack<Message*> are valid instantiations, even though int and Message* are
not "classes".
Implementing template member functions is somewhat different compared to the regular class
member functions. The declarations and definitions of the class template member functions
should all be in the same header file. The declarations and definitions need to be in the same
header file. Consider the following.
//B.H
template <class t>
class b
{
public:
b() ;
~b() ;
};
// B.CPP
#include "B.H"
template <class t>
b<t>::b()
{
}
template <class t>
b<t>::~b()
{
}
//MAIN.CPP
#include "B.H"
void main()
{
b<int> bi ;
b <float> bf ;
}
When compiling B.cpp, the compiler has both the declarations and the definitions available. At
this point the compiler does not need to generate any definitions for template classes, since
there are no instantiations. When the compiler compiles main.cpp, there are two instantiations:
template class B<int> and B<float>. At this point the compiler has the declarations but no
definitions!
While implementing class template member functions, the definitions are prefixed by the
keyword template. Here is the complete implementation of class template Stack:
//stack.h
#pragma once
template <class T>
class Stack
{
public:
Stack(int = 10) ;
~Stack() { delete [] stackPtr ; }
int push(const T&);
int pop(T&) ; // pop an element off the stack
int isEmpty()const { return top == -1 ; }
int isFull() const { return top == size - 1 ; }
private:
int size ; // Number of elements on Stack
int top ;
T* stackPtr ;
};
Using a class template is easy. Create the required classes by plugging in the actual type for the
type parameters. This process is commonly known as "Instantiating a class". Here is a sample
driver class that uses the Stack class template.
#include <iostream>
#include "stack.h"
using namespace std ;
void main()
{
typedef Stack<float> FloatStack ;
typedef Stack<int> IntStack ;
FloatStack fs(5) ;
float f = 1.1 ;
cout << "Pushing elements onto fs" << endl ;
while (fs.push(f))
{
cout << f << ' ' ;
f += 1.1 ;
}
cout << endl << "Stack Full." << endl
<< endl << "Popping elements from fs" << endl ;
while (fs.pop(f))
cout << f << ' ' ;
cout << endl << "Stack Empty" << endl ;
cout << endl ;
IntStack is ;
int i = 1.1 ;
cout << "Pushing elements onto is" << endl ;
while (is.push(i))
{
cout << i << ' ' ;
i += 1 ;
}
cout << endl << "Stack Full" << endl
<< endl << "Popping elements from is" << endl ;
while (is.pop(i))
cout << i << ' ' ;
cout << endl << "Stack Empty" << endl ;
}
Function Templates
To perform identical operations for each type of data compactly and conveniently, use function
templates. You can write a single function template definition. Based on the argument types
provided in calls to the function, the compiler automatically instantiates separate object code
functions to handle each type of call appropriately. The STL algorithms are implemented as
function templates.
Function templates are implemented like regular functions, except they are prefixed with the
keyword template. Here is a sample with a function template.
#include <iostream>
using namespace std ;
//max returns the maximum of the two elements
template <class T>
T max(T a, T b)
{
return a > b ? a : b ;
}
Using function templates is very easy: just use them like regular functions. When the compiler
sees an instantiation of the function template, for example: the call max(10, 15) in function
main, the compiler generates a function max(int, int). Similarly the compiler generates
definitions for max(char, char) and max(float, float) in this case.
#include <iostream>
using namespace std ;
//max returns the maximum of the two elements
template <class T>
T max(T a, T b)
{
return a > b ? a : b ;
}
void main()
{
cout << "max(10, 15) = " << max(10, 15) << endl ;
cout << "max('k', 's') = " << max('k', 's') << endl ;
cout << "max(10.1, 15.2) = " << max(10.1, 15.2) << endl ;
}
6. Discuss the theory of Exception specifications with suitable code snippets for each.
Ans.
C++ provides a mechanism to ensure that a given function is limited to throwing only a specified
list of exceptions. An exception specification at the beginning of any function acts as a
guarantee to the function's caller that the function will throw only the exceptions contained in
the exception specification.
>>-throw--(--+--------------+--)-------------------------------><
'-type_id_list-'
The type_id_list is a comma-separated list of types. In this list you cannot specify an incomplete
type, a pointer or a reference to an incomplete type, other than a pointer to void, optionally
qualified with const and/or volatile. You cannot define a type in an exception specification.
A function with no exception specification allows all exceptions. A function with an exception
specification that has an empty type_id_list, throw(), does not allow any exceptions to be
thrown.
An exception specification may only appear at the end of a function declarator of a function,
pointer to function, reference to function, pointer to member function declaration, or pointer
to member function definition. An exception specification cannot appear in a typedef
declaration. The following declarations demonstrate this:
Suppose that class A is one of the types in the type_id_list of an exception specification of a
function. That function may throw exception objects of class A, or any class publicly derived
from class A. The following example demonstrates this:
class A { };
class B : public A { };
class C { };
A function that overrides a virtual function can only throw exceptions specified by the virtual
function. The following example demonstrates this:
class A {
public:
virtual void f() throw (int, char);
};
class B : public A{
public: void f() throw (int) { }
};
class D : public A {
public: void f() throw (int, char, double) { }
};
*/The compiler allows B::f() because the member function may throw only exceptions of type
int. The compiler would not allow C::f() because the member function may throw any kind of
exception. The compiler would not allow D::f() because the member function can throw more
types of exceptions (int, char, and double) than A::f().
Suppose that you assign or initialize a pointer to function named x with a function or pointer to
function named y. The pointer to function x can only throw exceptions specified by the
exception specifications of y. The following example demonstrates this:
void (*f)();
void (*g)();
void (*h)() throw (int);
void i() {
f = h;
// h = g; This is an error.
}The compiler allows the assignment f = h because f can throw any kind of exception. The
compiler would not allow the assignment h = g because h can only throw objects of type int,
while g can throw any kind of exception.
class A {
public:
A() throw (int);
A(const A&) throw (float);
~A() throw();
};
class B {
public:
B() throw (char);
B(const A&);
~B() throw();
};
class C : public B, public A { };The following special functions in the above example have been
implicitly declared:
A. Instance Diagrams
Interaction diagrams are composed mainly of instances and messages. An instance is said to
be the realization of a class that is if we have a class Doctor, than the instances are Dr. Jones,
Dr. Smith, etc. In an object oriented application, instances are what exist when you instantiate a
class (create a new variable with the class as its datatype).
In the UML, instances are represented as rectangles with a single label formatted as:
instanceName: datatype
You can choose to name the instance or not, but the datatype should always be
specified. Below the name, you can also list the attributes and their values. In Visual Case, you
can map attributes from your class and enter new values specific to that instance. Attributes
need only be shown when they are important and you don’t have to specify and show all of the
attributes of a class.
Messages represent operation calls. That is, if an instance calls an operation in itself or
another class, a message is passed. Also, upon the completion of the operation a return
message is sent back to the instance that initiated the call.
Sequence represents the order in which the message is called. The sequence is redundant on
sequence diagrams, but required on collaboration diagrams
Iteration – an asterix (*) is shown to represent iteration if the message is called repeatedly.
Guard – an optional boolean expression (the result is either true or false) that determines if the
message is called.
Sequence diagrams emphasize the order in which things happen, while collaboration
diagrams give more flexibility in their layout. You can use whichever you prefer when drawing
interactions, as both show the same information.
Things to Note:
· The flow of time is shown from top to bottom, that is messages higher on the diagram happen
before those lower down
· The blue boxes are instances of the represented classes, and the vertical bars below are
timelines
· The arrows (links) are messages – operation calls and returns from operations
· The hide and show messages use guards to determine which to call. Guards are always shown
in square braces [ ] and represent constraints on the message (the message is sent only if the
constraint is satisfied)
· The messages are labeled with the operation being called and parameters are shown. You can
choose to enter the parameters or not – this is dependent upon their importance to the
collaboration being shown
· The sequence numbers are not shown on the messages as the sequence is intrinsic to the
diagram
Asynchronous Messages
You can specify a message as asynchronous if processing can continue while the message is
being executed. In the example below, the asynchronous call does not block processing for the
regular call right below. This is useful if the operation being called is run remotely, or in
another thread.
C) Collaboration Diagrams
Collaborations are more complex to follow than sequence diagrams, but they do provide the
added benefit of more flexibility in terms of spatial layout.
Above is our logon interaction shown as a collaboration diagram. Notice that each message is
numbered in sequence, because it is not obvious from the diagram, the order of the messages.
Lollipop Interfaces
Another advantage over the sequence diagram is that collaboration diagrams allow you to
show lollipop interfaces.
Suppose that our DatabaseAccess class implemented an interface called Queryable. If the
logon manager only has access to the interface, we can show that the message is called through
the interface by including a lollipop interface on the diagram. The stick of the lollipop indicates
that the class DatabaseAccess realizes Queryable.