Vous êtes sur la page 1sur 25

February 2010

Master of Computer Application (MCA) –


Semester 2
MC0066 – OOPS using C++
Assignment – Set 1

1. Describe the following:

A) Basic Components and structure of C++ program

Ans –

The C++ is a superset of C. At the basic level, the programs look


similar in both C and C++. Every statement in C++ ends with a
semicolon (;). All the reserved words have to be written in small case and
the c++ compiler is case sensitive. Data in programming languages are
stored in variables. To create a variable, the variable should support an
inbuilt datatype. The variable is a name given to a particular location in
the memory and the value stored in a variable can be altered during
program execution. The datatypes supported in C++ are listed below

Basic Datatypes in c++

Data Type Size (inValues that can be taken


bytes)
Int 2 -32768 to 32767
Bool 1 False and true / 0 and 1
Char 1 -128 to 127
Long 4 -2,147,483,648 to 2,147,483,647
Float 4 3.4 X 10-38 to 3.4 X 1038 (Precision 7)
Double 8 1.7 X 10-308 to 1.7 X 10308 (Precision 15)
Long double 10 3.4 X 10-4932 to 1.1 X 104932 (Precision 19)
Unsigned int 2 0 to 65,535

Variables can be named according to following rules

· Can comprise of 1 to 8 alphabets, digits or underscore

· First character should be an alphabet

· Names are case sensitive


· Reserve words of c++ cannot be used

Variables have to be declared before using them in the program. The


declaration is done in the following way:

datatype variablename

Eg: int data ;

The above declaration declares a integer variable named data. The


value stored in int data by default is a junk value. Values can also be
assigned to the variable during declarations or initialized separately
using the assignment operator =.

Eg: int data=0;

Or

int data;

data=0;

Constants are those which do not change during execution of a program.


The constants in C++ can be numeric, character or string constants.
Examples of each are shown in table 1.3

Example of Constants

Constant
Example Constraints
Numeric 23000 Can be negative or positive,
Constant cannot contain blanks or
450.6 (Floatingcommas, or $
point)
Character ‘A’ Any character enclosed within
Constant single quotes, represented by
unique ASCII number in the
memory
String “Hello” Set of characters enclosed in
Constant double quotes, last character
in the string is null character
‘\0’

Operators supported in C++ are listed below. Unary operators are used
with one operand and binary operator is used with two operands.
Operators in C++

Arithmetic Type Action


Operators
- Unary asSubtraction for binary and
well asminus for unary
binary
+ Binary Addition
* Binary Multiplication
/ Binary Division
% Binary Modulus (remainder after
dividing)
– Unary Decrement value by one
++ Unary Increment value by one
Relational Type Action
Operators
> Binary Greater than
>= Binary Greater than or equal
< Binary Less than
<= Binary Less than equal
== Binary Comparision for equality
!= Binary Comparision for inequality
Logical Type Action
Operators
&& Binary AND
|| Binary OR
! Unary NOT

Lets begin with a simple c++ program

// sum.cpp
#include<iostream.h>
void main()
{
int a,b,sum;
cout<<”Please enter any two numbers”<<endl;
cin>>a>>b;
sum=a+b;
cout<<”Sum of two numbers is ”<<sum;
}

B) Steps in compiling and executing a C++ program


The above discussion should also be followed by giving
example programs for 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.

Compiling and Linking

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 following in C++:


A) if statements

Ans –

If statement

Syntax : if (expression or condition)


{ statement 1;
statement 2;
}
else
{ statement 3;
statement 4;
}

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.

Following example program implements the if statement.

// 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 statement can be nested in another if statement to check multiple


conditions.

If (condition1)
{ if (condition 2)
{ statement1;
Statement2;
}
else if (condition3)
{statement3;
}
}
else statement4;

The flowchart of the above example is shown below

Multiple conditions can be checked using logical && operator(AND) and ||


operator (OR).

If ((condition1) && (condition2))


statement1;
else
statement2;

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.

The flowchart for the switch statement is shown below


The following program implements the switch 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.

C) conditional operator, with appropriate programming


examples.

Ans –

Conditional Operator

Conditional operator (?:) is a handy operator which acts like a


shortcut for if else statement. If you had to compare two variables a and
b and then depending on which is larger, you wanted to store that
variable in another variable called large. You would do this using if else
statement in the following way:

if (a>b)
large=a;
else
large=b;
The above can be done using conditional operator in the following way:
large= (a>b) ? a : b ;

3. Write a program in C++ for matrix multiplication.


The program should accept the dimensions of both the
matrices to be multiplied and check for compatibility
with appropriate messages and give the output.

Ans –

#include<iostream.h>
#include<conio.h>
#include<process.h>
void main()
{ clrscr();
int a[10][10],b[10][10],p[10][10],r,c,m,n,i,j,s;
cout<<"Enter number of rows of first matrix: "; cin>>r;
cout<<"Enter number of columns of first matrix: "; cin>>c;
cout<<"Enter number of rows of second matrix: "; cin>>m;
cout<<"Enter number of columns of second matrix: "; cin>>n;
if (c!=m) cout<<"\nMatrices cannot be multiplied", getch(), exit(0);
clrscr();
cout<<"Enter elements of first matrix...\n\n";
for (i=0;i<r;i++)
for (j=0;j<c;j++) cin>>a[i][j];
cout<<"Enter elements of first matrix...\n\n";
for (i=0;i<m;i++)
for (j=0;j<n;j++) cin>>b[i][j];
clrscr();
cout<<"1st matrix...\n";
for (i=0;i<r;i++)
{ for (j=0;j<c;j++) cout<<" "<<a[i][j]; cout<<"\n"; }
cout<<"2nd matrix...\n";
for (i=0;i<m;i++)
{ for (j=0;j<n;j++) cout<<" "<<b[i][j]; cout<<"\n"; }

cout<<"\nProduct...\n";
for (i=0;i<r;i++)
{ for (j=0;j<n;j++)
{ p[i][j]=0; for (s=0;s<c;s++) p[i][j]+=a[i][s]*b[s][j]; cout<<" "<<p[i][j]; }
cout<<"\n"; }
getch();
}

4. Describe and Demonstrate the concept of Pass by


Value and Pass By Reference using appropriate
programming examples of your own.

Ans –

Data can be passed to functions in two ways. One method is


passing by value. The fact function discussed in previous section
implements passing by value. In this way of passing variables, a copy of
the variable(main program) is created during function call with the name
specified in the function and initialized with the value in the original
variable. All the operations in the function is then performed on the
function variable. The values in the variables declared in the main
program remains unchanged by the function operations.

Another alternative to passing arguments is passing by


reference. In passing by reference, no copy of the variable is created.
However, the variables in the main program are referred to by different
name in the function. Since no copy is created, when the values in the
function variables are modified, the values in the variables in the main
program are also modified. Passing by reference provides an easy
mechanism for modifying the variables by functions and also enables to
return multiple variables.

To pass arguments by reference, all the variable names in the


argument list should be prefixed with & (ampersand) or address of
operator during function declaration and definition. The following
example shows the implementation of passing by reference.

Function call is same for passing by reference.

//passingbyreference.cpp
# include <iostream.h>
int swap(int& m, int& n); // function declaration
void main()
{
int a,b ;
cout<< “enter two numbers”;
cin>>a>>b;
swap(a,b);
cout<<”The value of a is”<<a<<endl;
cout<<”The value of b is”<<b<<endl;
}
void swap(int& m, int& n)
{ int temp;
temp=m;
m=n;
n=temp;
}

In the above program, the variables a and b are passed by


reference which implies that they will be accessed directly. The variables
are however will be referred as m and n in the function and are swapped.
The result is that the function swaps the values in the original variables a
and b.

5. Describe the concept of Multiple Inheritance with a


programming example of your own.

Ans –

You can derive a class from any number of base classes. Deriving a
class from more than one direct base class is called multiple inheritance.

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 { /* … */ };

The following inheritance graph describes the inheritance


relationships of the above example. An arrow points to the direct base
class of the class at the tail of the arrow:

The order of derivation is relevant only to determine the order of


default initialization by constructors and cleanup by destructors.

A direct base class cannot appear in the base list of a derived class more
than once:

class B1 { /* … */ }; // direct base class

class D : public B1, private B1 { /* … */ }; // error

However, a derived class can inherit an indirect base class more than
once, as shown in the following example:

class L { /* … */ }; // indirect base class

class B2 : public L { /* … */ };
class B3 : public L { /* … */ };

class D : public B2, public B3 { /* … */ }; // valid

In the above example, class D inherits the indirect base class L once
through class B2 and once through class B3. However, this may lead to
ambiguities because two sub objects of class L exist, and both are
accessible through class D. You can avoid this ambiguity by referring to
class L using a qualified class name. For example:

B2::L

or

B3::L.

6. Describe the concept of Virtual Functions with a


programming example of your own.

Ans –

Virtual means existing in effect but not in reality. Virtual functions


are primarily used in inheritance. Let us suppose you have a class base
as shown in the following program and two classes derv1 and derv2 are
publicly derived from class base. You would like to create a pointer that
points to any of the derived class objects. If you create a pointer of
derv1, then it can point to derv1 object only. Compiler will complain if
you assign any other object is assigned to the pointer. The solution is to
create a pointer to Base class.

// objectptr.cpp
# include <iostream.h>
class base
{ public:
void show()
{cout<<“base”<<endl;}};
class derv1:public base
{ public:
void show()
{cout<<“derv1”<<endl;}};
class derv2: public base
{ public:
void show()
{cout<<“derv2”<<endl;}};
void main()
{
derv1 dv1;
derv2 dv2;
base *ptr;
ptr=&dv1;
ptr->show();
ptr=&dv2;
ptr->show();
}

The output of the above program will be surprisingly:

base

base

Even though the address of derived classes is assigned to the


pointer, the compiler executes the base class function. However, if the
base class function is made virtual, we get the desired result. In the
following program we have made the base class function show() as
virtual function by prefixing with the keyword virtual.

//virtual.cpp
# include <iostream.h>
class base
{ public:
virtual void show() // virtual function
{cout<<“base”<<endl;}};
class derv1:public base
{ public:
void show()
{cout<<“derv1”<<endl;}};
class derv2: public base
{ public:
void show()
{cout<<“derv2”<<endl;}};
void main()
{
derv1 dv1;
derv2 dv2;
base *ptr;
ptr=&dv1;
ptr->show();
ptr=&dv2;
ptr->show();
}

By declaring the base class function as virtual, we now get the output as:

derv1
derv2

In the above program, depending on the contents in the pointer,


the compiler decides which class function to call during runtime. This is
known as late binding or dynamic binding.

Virtual functions are for just name sake and will not be executed
many a times. If the virtual function has no specific role in the base but
just declared for enabling the derived class objects access through
pointers, the function can be declared as a pure virtual function. A pure
virtual function is one which does not have any body. Virtual functions
declared by equating it to zero as shown below:

virtual void show()=0;

In inheritance, many a times you would create a class just for


grouping data or functionality but the class do not have any instances of
its own. Such classes which does not have any objects are known as
abstract classes. For example, there is a class known as employee and
there are many classes derived from this class such as manager, worker
etc. In the program, the employee class brings together the common
data and functions to all the subclasses and to avoid coding same
functionality in each and every class. Here employee class is the abstract
class.

7. Illustrate with suitable examples various file


handling methods in C++.

Ans –

Opening a File – Different Methods

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.

Consider the following code example:

#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.

ifstream OpenFile(char *filename, int open_mode);

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:

ios::in Open file to read


ios::out Open file to write
ios::app All the date you write, is put at the end of the file. It calls
ios::out
ios::ate All the date you write, is put at the end of the file. It does not
call ios::out
ios::trunc Deletes all previous content in the file. (empties the file)
ios::nocreat If the file does not exists, opening it with the open() function
e gets impossible.
ios::norepla If the file exists, trying to open it with the open() function,
ce returns an error.
ios::binary Opens the file in binary mode.
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:

Hi! This is test from www.cpp-home.com!

Running the above code, will add “That’s new!” to it, so it will look this
way:

Hi! This is test from www.cpp-home.com!That’s new!

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:

fstream File(“cpp-home.txt”, ios::in | ios::out);

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();
}

Let us now understand the above program:

fstream File(“test.txt”, ios::in | ios::out);

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.

File << “Hi!”;

I am sure the reader is aware of this and hence the explanation for this
statement is redundant.

static char str[10];

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:

· ios::beg – to put it in the beginning of the file

· ios::end – to put it at the end of the file

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);

If you want to go 40 characters after, just write:

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:

· You go to the end (ios::end)

· You go 5 characters before the end (-5)

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.

File >> str;

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:

Hi! Do you know me?

Using File >> str, will put just “Hi!” to the str array. And, as what we put
in the file was “Hi!” we don’t need to do a while loop, that takes more
time to code. That’s why this technique was used. By the way, in the
while loop for reading, that was used so far, the program reads the file,
char by char. But you can read it word by word, this way:

char str[30]; //the word can’t be more than 30 characters long


while(!OpenFile.eof()){
OpenFile >> str;
cout << str;
}
You can also read it line by line, this way:
char line[100]; //a whole line will be stored here
while(!OpenFile.eof()) {
OpenFile.getline(line,100); //where 100 is the size of the array
cout << line << endl;
}

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".

Implementing Class Template Member Functions


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 //B.CPP //MAIN.CPP


template <class t> #include "B.H" #include "B.H"
class b { template <class t> void main() {
public: b<t>::b() { b<int> bi;
b(); } b <float> bf;
~b(); template <class t> }
}; b<t>::~b() {
}

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

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:

Pushing elements onto fs


1.1 2.2 3.3 4.4 5.5
Stack Full.
Popping elements from fs
5.5 4.4 3.3 2.2 1.1
Stack Empty
Pushing elements onto is
1 2 3 4 5 6 7 8 9 10
Stack Full
Popping elements from is
10 9 8 7 6 5 4 3 2 1

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.)

There are two advantages:

· typedef’s are very useful when "templates of templates" come into


usage. For example, when instantiating an STL vector of int’s, you could
use:

typedef vector<int, allocator<int> > INTVECTOR;

· If the template definition changes, simply change the typedef definition.


For example, currently the definition of template class vector requires a
second parameter.
typedef vector<int, allocator<int> > INTVECTOR;
INTVECTOR vi1;
In a future version, the second parameter may not be required, for
example,
typedef vector<int> INTVECTOR;
INTVECTOR vi1;

Vous aimerez peut-être aussi