Documente Academic
Documente Profesional
Documente Cultură
18 C/C++ (Part 2)
Copyright© Department of Computer Science, University of Regina
Originally written in 1998 by Zhiwei Wang
Last updated in July 2001 by Zhiwei Wang
When a C++ program is running, the following four built-in streams are automatically
opened:
Example
/*********************************************************
*
* FILE NAME: basics.cpp *
* AUTHOR: Zhiwei Wang *
* DATE: May. 1997 *
* DESCRIPTION: An example for simple I/O stream *
***********************************************************/
#include <iostream>
main(){
char name[50];
cout << "Please enter your name: ";
cin >> name;
cout << "Hello, " << name << ".\n";
cout << "My name is Zhiwei." << endl;
// 'endl' can be used in place of "\n"
return 0;
}
// End of program
//***********************************************************
There are three member functions defined by ios that set the format parameters, namely:
int width(int w);
This function sets the field width. Here w is the field width. The returned value
is the previous width. If a value uses less than the specified width, the field will
be padded with fill character. The default fill character is space.
int precision(int p);
This function sets precision to p. The returned value is the previous precision.
Precision determines the number of digits to be displayed after the decimal
point. The default precision is 6.
char fill(char ch);
This function sets the fill character to ch. The previous fill character is returned.
Here is an example that illustrates these functions
/***************************************************************
FILE NAME: example1.cpp
AUTHOR: Zhiwei Wang
DATE: May 1998
DESCRIPTION:
An example demonstrating how to use the width(),
precision(), and fill() functions.
*****************************************************************/
#include <iostream>
main()
{
double pi = 3.1415926535;
cout << pi << endl;
cout.precision(3);
cout << pi << endl;
cout.precision(3);
cout.width(10);
cout << pi << endl;
cout.precision(3);
cout.width(10);
cout.fill('0');
cout << pi << endl;
return 0;
}
/* Output:
mercury[105]% a.out
3.14159
3.14
3.14
0000003.14
*/
Another way to perform formatted I/O is using manipulators. Manipulators are special
functions that can be used to format i/o. In the previous example, 'endl' is a manipulator
to output a newline character and flush the stream.
/*****************************************************************
FILE NAME: example2.cpp
AUTHOR: Zhiwei Wang
DATE: May. 1998
DESCRIPTION:
An example demonstrating how to use the manipulators.
*****************************************************************/
#include <iostream>
#include <iomanip>
return 0;
}
/* Output:
100
64
3.14159
0000003.14
*/
To perform file I/O, you must include the header file <fstream>. It defines the classes
ifstream, ofstream, and fstream, which are needed to open files.
Example:
/***********************************************************
* FILE NAME: readfile.cpp *
* AUTHOR: Zhiwei Wang *
* DATE: May. 1997 *
* DESCRIPTION: An example for simple disk file I/O *
************************************************************/
#include <iostream>
#include <fstream>
#include <string.h>
//END OF PROGRAM
//************************************************************/
In C++, the class forms the basis of object-oriented programming. It is the basic unit of
encapsulation. Classes define the nature of objects. To create a class, use the key word
class. Here is the syntax:
class class_name {
private data and functions
access_specifier:
data and functions
access_specifier:
data and functions
access_specifier:
data and functions
.
.
.
access_specifier:
data and functions
} object_list;
Example 1
class vector {
public:
float x, y;
};
In this example, we define a class named vector The vector class has
two data members: x and y that are float numbers. Both x and y are
public, which means they are accessible to other parts of the program.
vector a, b, c;
Example
/*********************************************************
Filename: sum.cpp Date: April 4, 1997
Author: Zhiwei Wang
Student Number:
Description: This program calculates the sum of two vectors.
**********************************************************/
#include <iostream>
class vector {
public:
int x, y;
};
main(){
vector a, b, c;
a.x = 15;
a.y = 20;
b.x = 100;
b.y = 40;
c.x = a.x + b.x;
c.y = a.y + b.y;
cout<< "The x-coordinate of vector c is: "<< c.x<<"\n";
cout<< "The y-coordinate of vector c is: "<< c.y<<"\n";
return 0;
}
//Output:
//The x-coordinate of vector c is: 115
//The y-coordinate of vector c is: 420
// End of Program
//********************************************************************
7.18.10.2. Encapsulation and Information Hiding
Example:
/************************************************************
Filename: classes.cpp
Author: Zhiwei Wang
Date: May, 1997
Description: A simple class example
************************************************************/
#include <iostream>
public:
int income(void); // with two methods
void initialize(int, int);
};
main(){
person a, b;
a.initialize(12, 10);
b.initialize(8, 8);
cout << "The income of person a is " << a.income() << "\n";
cout << "The income of person b is " << b.income() << "\n";
return 0;
}
// End of Program
//**********************************************
Example:
/************************************************************
Filename: structor.cpp
Author: Zhiwei Wang
Date: May, 1997
Description: A simple class example with constructor and
destructor.
************************************************************/
#include <iostream>
using namespace std;
public:
person(void);
~person(void);
int income(void); // with two methods
void initialize(int, int);
};
person:: person(void) {
hour = 40;
rate = 15;
}
person::~person(void) {
hour = 0;
rate = 0;
cout << "Personal information deleted.\n";
}
main(){
person a, b;
cout << "The income of person a is " << a.income() << "\n";
cout << "The income of person b is " << b.income() << "\n";
a.initialize(12, 10);
b.initialize(8, 8);
cout << "The income of person a is " << a.income() << "\n";
cout << "The income of person b is " << b.income() << "\n";
return 0;
}
/* output:
The income of person a is 600
The income of person b is 600
The income of person a is 120
The income of person b is 64
Personal information deleted.
Personal information deleted.
*/
// End of Program
//************************************************************
7.18.11.1. Namespaces
Example:
// in header file cstdlib:
namespace std
{
...
int abs(int);
...
}
Example:
// Filename: hiusingname.cpp
#include <iostream>
using namespace std;
main() {
cout << "Hi" << endl;
}
Notice that in the preprocessor directive "#include <iostream>", the header file
doesn't have the suffix .h. After the "#include", a using directive follows. When you
compile this program (hiusingname.cpp) in hercules, you need to use the "LANG'
option:
If you use the older header file <iostream.h>, you don't need the using directive:
Example:
// filename: hi.cpp
#include <iostream.h>
main() {
cout << "Hi" << endl;
}
When you compile this program (hi.cpp), you don't need to use the "LANG" option:
hercules[1]% CC hi.cpp
Class scope: The scope of class members is within the classe (struct,
union)
Example:
#include <iostream>
void main() {
cout << num << endl; // global num 0
int num = 3;
myFunction3(); // 0
cout << num << endl; // 3
cout << myNamespace::num << endl; // 1
myFunction2(); // 4
myFunction(num); // 9
}
// out put: 0 0 3 1 4 9 in each line
void myFunction3() {
cout << num << endl;
}
void myFunction2() {
int num = 4;
cout << num << endl;
}
class myClass {
public:
static int share;
int num; // class
};
int myClass::share;
void main() {
myClass o1, o2;
o1.share = 1;
o1.num = 1;
cout << o1.share << endl;
cout << o1.num << endl;
o2.share = 2;
o2.num = 2;
cout << o2.share << endl;
cout << o2.num << endl;
cout << o1.share << endl;
cout << o1.num << endl;
}
int myClass::share;
void main() {
myClass o1;
o1.setShare(1);
o1.setNum(1);
cout << o1.getShare() << endl;
cout << o1.getNum() << endl;
myClass::setShare(2);
cout << o1.getShare() << endl;
cout << o1.getNum() << endl;
}
7.18.12.1. Polymorphism
In C++, you can use the same name for two or more functions, providing
that the number of parameters or the data type of parameters are
different. This is called function overloading. Function overloading
is one way to realize polymorphism, which means to allow one interface
to be used with multiple methods.
Example
/***********************************************************
Filename: overload.cpp
Author: Zhiwei Wang
Date: July, 1997
Description: A simple example of function overloading
************************************************************/
#include <iostream>
main()
{
int num = 12;
float num2 =12.0;
cout << "The number is " << f(num) << "\n";
cout << "3 times 12 is " << f(num2) << "\n";
cout << "The average of 12 and 36 is " << f(12.0, 36.0) << "\n";
return 0;
}
/* Output:
The number is 12
3 times 12 is 36
The average of 12 and 36 is 24
*/
// End of Program
//*************************************************
The output of the previous program shows that the C++ compiler knows
which function should be invoked by analyzing the parameter lists.
7.18.12.2. Ambiguity
C++ has a feature called 'automatic type conversion', which means C++
will automatically attempt to convert the arguments used to call a
function into the data type expected by the function. In some
situation, this makes the compiler unable to choose between different
overloaded functions. This situation is said to be ambiguous.
Example
/************************************************************
Filename: opover.cpp
Author: Zhiwei Wang
Date: July, 1997
Description:
overload operators using member functions.
************************************************************/
#include <iostream>
vector vector::operator+(vector v) {
vector temp;
temp.x = v.x + x;
temp.y = v.y + y;
return temp;
}
float vector::operator*(vector v) {
return (v.x * x + v.y * y);
}
main()
{
vector f1(19, 97), f2(7, 11);
cout << "vector 1 is: ";
f1.display();
cout << "vector 2 is: ";
f2.display();
cout << "The sum of the two vectors is: ";
(f1+f2).display();
cout << "The inner product of the two vectors is: " << f1 * f2 <<
endl;
return 0;
}
(f1+f2).display();
possible.
class vector {
float x, y;
public:
vector(){};
vector(float a, float b) {x=a; y=b;}
void display() {cout << "x=" << x << ", y=" << y << endl;}
friend vector operator+(vector v1, vector v2);
friend float operator*(vector v1, vector v2);
};
main()
{
vector f1(19, 97), f2(7, 11);
cout << "vector 1 is: ";
f1.display();
cout << "vector 2 is: ";
f2.display();
cout << "The sum of the 2 vectors is: ";
(f1+f2).display();
cout << "The inner product of the two vector is: "
<< f1 * f2 << endl;
return 0;
}
// End of Program
//***********************************************
vector vector::operator+(vector v) {
cout << "This is a weird addition, isn't it?\n";
return v;
}
main()
{
vector f1(19, 97), f2(7, 11);
f1 + f2;
return 0;
}
/* Output:
This is a weird addition, isn't it?
*/
// End of Program
//*************************************************
It is suggested that when you overload an operator, you have
sufficient reason to do so.
7.18.14. INHERITANCE
Example
/************************************************************
Filename: 2d3d.cpp
Author: Zhiwei Wang
Date: July, 1997
Description: This program demonstrates how a derived class
(measure_3d) inherits the base class (measure_2d).
************************************************************/
#include <iostream>
using namespace std;
main(){
measure_3d box(6);
/* Output:
length=2
width=4
The area occupied by the box is 8
height=6
The volume of the box is 48
*/ // End of Program
//*************************************************
Example
/************************************************************
Filename: 2d3d_a.cpp
Author: Zhiwei Wang
Date: July, 1997
Description: This program demonstrates how a derived class
(measure_3d) inherits the base class (measure_2d).
************************************************************/
#include <iostream>
main(){
measure_3d box(6);
// access members of base class
box.set(2, 4);
box.display();
cout << "The area occupied by the box is " << box.area() << "\n";
// access members of derived class
box.display_height();
cout << "The volume of the box is " << box.volume() << "\n";
return 0;
}
Compiling the altered program .cpp, you will get:
mercury[13]% CC 2d3d_a.cpp
"2d3d_a.cpp", line 24: error(3346): member "measure_2d::length" is
inaccessible
int volume() { return length * width * height;}
^
"2d3d_a.cpp", line 24: error(3346): member "measure_2d::width" is
inaccessible
int volume() { return length * width * height;}
^
2 errors detected in the compilation of "2d3d_a.cpp".
When the access specifier is private, all public and protected members of the base class
become private members of the derived class. For example, let us keep everything in
'2d3d.cpp' unchanged, except replacing the process specifier 'public' with 'private'. The
new program is as below:
/************************************************************
Filename: 2d3d.cpp
Author: Zhiwei Wang
Date: July, 1997
Description: This program demonstrates how a derived class
(measure_3d) inherits the base class (measure_2d).
************************************************************/
#include <iostream>
main(){
measure_3d box(6);
// error: cannot access members of base class
box.set(2, 4);
box.display();
cout << "The area occupied by the box is " << box.area() << "\n";
// access members of derived class
box.display_height();
cout << "The volume of the box is " << box.volume() << "\n";
return 0;
}
// End of Program
//****************************************************
A derived class can be used as a base class for another derived class, this is referred to
as multiple inheritance. A class can inherit more than one classes, this is called
inheriting multiple base classes. In the following program, class 'measure_2d' inherits
'measure_l' and 'measure_w', this is an example of inheriting multiple base classes; class
'measure_3d' inherits 'measure_2d', while 'measure_2d' itself is a derived class, this is an
example of multiple inheritance.
/************************************************************
Filename: m_inherit.cpp
Author: Zhiwei Wang
Date: July, 1997
Description: This program gives examples of multiple
inheritance and inheriting multiple classes.
demonstrates how a derived class
************************************************************/
#include <iostream>
main(){
measure_3d box(6);
box.set(2, 4);
box.display();
cout << "The area of the box is " << box.area() << "\n";
box.display_height();
cout << "The volume of the box is " << box.volume() << "\n";
return 0;
}
// End of Program
//***************************************************
An array is a collection of variables of the same data type. Its elements are referenced
by the name of the array followed by a pair of square brackets with an index number in
them. For example, the following statement declares an array of 100 integers.
int my_array[100];
The syntax for declaring an object array is the same as it is for any other data types,
except that the forms to initialize an array are different according to how many
parameters required by the constructor function.
class Vector_1 {
int x;
public:
void set_x(int num) {x=num;}
int get_x() {return x;}
};
main(){
Vector_1 my_array[4];
my_array[0].set_x(1);
my_array[1].set_x(9);
my_array[2].set_x(9);
my_array[3].set_x(7);
for (int i=0; i<4; i++) {
cout << my_array[i].get_x() << endl;
}
return 0;
}
// End of Program
//****************************************************
The following example is similar to the previous one but this time class vector_1 has a
constructor function which requires one parameter. In this case, the array can be
initialized by using a list of arameters.
/*********************************************************
Filename: vector1.cpp
Description:
**********************************************************/
#include <iostream>
class Vector_1 {
int x;
public:
Vector_1 (int num) {x=num;} // constructor can not return a value.
int get_x() {return x;}
};
main(){
Vector_1 my_array[4] = {1, 9, 9, 7};
for (int i=0; i<4; i++) {
cout << my_array[i].get_x();
}
cout << endl;
return 0;
}
// End of Program
//****************************************************
The following example illustrates how to initialize an array of objects when the
constuctor requires more than one parameters.
/*********************************************************
Filename: vector2.cpp
Date: July 24, 1997
Author: Zhiwei Wang
Student Number:
Description:
Declaring an array of objects.
**********************************************************/
#include <iostream>
class Vector_2 {
int x, y;
public:
Vector_2 (int num1, int num2) {x=num1; y=num2;}
int get_x() {return x;}
int get_y() {return y;}
};
main(){
Vector_2 my_array[2] = {vector_2(1, 9), vector_2(9, 7)};
for (int i=0; i<2; i++) {
cout << my_array[i].get_x() << my_array[i].get_y();
}
cout << endl;
return 0;
}
// End of Program
//****************************************************
The syntax to declare a pointer to an object is the same as that to declare a pointer to
any other data types. Here is an example:
Example:
/************************************************************
Filename: pointer1.cpp
Author: Zhiwei Wang
Date: July, 1997
Description:
An example illustrating how to declare a pointer to object,
and how to assign the address of an object to the pointer.
************************************************************/
#include <iostream>
class vector {
int x, y;
public:
vector(){};
vector(int a, int b) {x=a; y=b;}
void display() {cout << "x=" << x << ", y=" << y << endl;}
};
main(){
vector *p; // p is a pointer to vector
vector f1(19, 97), f2(7, 12);
p = &f1; // assigning the address of f1 to p
cout << "vector 1 is: ";
p->display(); // using an arrow to access the member function
cout << "vector 2 is: ";
f2.display();
return 0;
}
In the preceding example, 'p' is a pointer to 'vector'. When you use a pointer (e.g. 'p') to
access a member function, you use the arrow operator instead of a dot.
Addition and substraction can be applied to pointers. When you declare an array of
objects, the objects are stored in contiguous memory locations. If a pointer p is assigned
the address of an array, then p points to the first item of the array, p+1 points to the
second item, p+2 points to the third item, etc.
Every member function of an object has an implicit argument called this that is a pointer
to the object. You can use the this pointer to refer to the object itself. This is especially
useful when you overload an operator.
Example:
/************************************************************
Filename: this.cpp
Author: Zhiwei Wang
Date: July, 1997
Description:
An example showing how to use the 'this' pointer to refer to
the calling object.
************************************************************/
#include <iostream>
class vector {
int x, y;
public:
vector(){};
vector(int a, int b) {x=a; y=b;}
void display() {cout << "x=" << x << ", y=" << y << endl;}
vector operator++();
};
vector vector::operator++() {
x++;
y++;
return *this;
}
main(){
vector f1(19, 97);
cout << "vector 1 is: ";
f1.display();
++f1;
cout << "After increment, it is: ";
f1.display();
return 0;
}
// End of Program
C++ has a special type of pointer called 'a pointer to a class member'. A pointer to a
class member provides an offset into an object at which the member can be found. Since
a point to a class member is not a true pointer in the normal sense, to access a member,
you use the special operators .* and ->* instead of using the operators . and ->.
When declaring pointers to members, you must specify the class and use the scope
operator. The following is an example. Please pay attention to the syntax of each
declaration.
/************************************************************
Filename: member.cpp
Author: Zhiwei Wang
Date: July, 1997
Description:
An example of using pointers to class members.
************************************************************/
#include <iostream>
class vector {
public:
int x, y;
vector(){};
vector(int a, int b) {x=a; y=b;}
void display() {cout << "x=" << x << ", y=" << y << endl;}
};
main(){
int vector::*d; // d is a pointer to data member.
void (vector::*f)(); // f is a pointer to function member.
vector f1(19, 97), f2(7, 12);
vector *p; // p is a normal pointer to object.
p = &f2; // assign the address of f2.
d = &vector::x; // get offset of x.
f = &vector::display; // get offset of display().
// access data member.
cout << "The first value of f1 is " << f1.*d << endl;
// access function member.
(f1.*f)();
// access data member via pointer 'p'.
cout << "The first value of f2 is " << p->*d << endl;
// access function member via pointer 'p'.
(p->*f)();
return 0;
}
// End of Program
7.18.17. REFERENCES
In C, there are two ways to pass arguments to a function: 'call by value' and 'call by
references'. C++ has a feature to do 'call by reference' automatically.
main(){
int a = 1, b = 2;
cout << " a = " << a << "\tb = " << b << endl;
swap(a, b);
cout << "After wrong swap:\n";
// The value WILL NOT be changed.
cout << " a = " << a << "\tb= " << b << endl;
return 0;
}
In order to change the value of an argument, we need to use the method called 'pass by
references'. To do this, first, we need to locate the argument. This means that we should
pass the address of the argument to the function. For example, when we call the
function swap(), we should precede arguments 'a' and 'b' with the address operator '&':
swap(&a, &b);
Second, we need to tell the function that it is the contents, not the address, of the
parameters that should be processed. This means that, in the definition of the function,
we need to put the dereferencing operator '*' in front of the parameters:
/************************************************************
Filename: swap2.cpp
Author: Zhiwei Wang
Date: July, 1997
Description:
This program illustrates that 'call by reference' will
change the value of the original arguments
************************************************************/
#include <iostream>
using namespace std;
main(){
int a = 1, b = 2;
cout << " a = " << a << "\tb = " << b << endl;
swap(&a, &b);
cout << "After swap:\n";
cout << " a = " << a << "\tb = " << b << endl;
return 0;
}
C++ has a feature called 'reference arguments'. The use of reference arguments will
automatically involve the 'pass by reference' mechanism. When you call the function,
you don't need to use '&' to explicitly pass the address; When you write the body of the
function, you don't need the '*' sign neither. The only thing you need to do is to precede
the argument with a '&' sign in the header of the function definition. Of course the
prototype should be changed accordingly. The following is the 'reference arguments'
version of the two preceding programs.
/************************************************************
Filename: swap2.cpp
Author: Zhiwei Wang
Date: July, 1997
Description:
This program illustrates that 'call by reference' will
change the value of the original arguments
************************************************************/
#include <iostream>
main(){
int a = 1, b = 2;
cout << " a = " << a << "\tb = " << b << endl;
swap(a, b);
cout << "After swap:\n";
cout << " a = " << a << "\tb = " << b << endl;
return 0;
}
Example
class person {
public:
virtual void greeting() { cout << "Hello!\n";}
};
class person {
public:
virtual void greeting() { cout << "Hello!\n";}
};
main(){
person *p, b;
woman d1;
man d2;
p = &b;
p->greeting();
p = &d1;
p->greeting();
p = &d2;
p->greeting();
return 0;
}
/* Output:
Hello!
Hello!
Hello! Lady first.
*/
A pure virtual function is a virtual function that has no definition in the base class. The
format to declare a pure virtual function is:
When a virtual function is made pure, all derived classes must provide their own
definition, otherwise a compile-time error will occur.
An abstract class is a class that contains pure virtual function(s). It is used as a
foundation for derived classes but cannot be used directly to create objects. However,
pointers to an abstract class are legal. This allows run-time polymorphism.
/************************************************************
Filename: abstract.cpp
Author: Zhiwei Wang
Date: July, 1997
Description: A simple example of using abstract class
An abstract class is a class that contains pure
virtual function(s). A pure virtual function is
a virtual function that has no definition
in the base class. An abstract class cannot be used
directly to create objects. However, pointers to an
abstract class are allowed.
************************************************************/
#include <iostream>
main(){
// Abstract class cannot be used to create object 'b'.
// so comments out the following line
// person *p, b;
person *p;
woman d1;
man d2;
p = &d1;
p->greeting();
p = &d2;
p->greeting();
return 0;
}
/* Output:
Hello!
Hello! Lady first.
*/
// End of Program
7.18.19. TEMPLATES
7.18.19.1. Generic Functions
A generic function (also called template function) is a function that defines a general
algorithm applicable to various types of data. A generic function is defined with the
keyword template:
template <class Ttype> ret-type func-name (parameter list) {
// body of function
}
Ttype is a placeholder for the data type used by the function. In the following
example,
the function 'swap()' is a generic function that can be used to swap two numbers,
characters, etc.
/************************************************************
Filename: swap.cpp
Description: A simple example of using template
************************************************************/
#include <iostream>
// a function template
template <class Whatever> void swap(Whatever &a, Whatever &b) {
Whatever temp;
temp = a;
a = b;
b = temp;
}
main(){
cout << "swap() can be used to swap two integers:\n";
int i=1, j=2;
cout << "Original:\ti=" << i << ";\tj=" << j << ".\n";
swap(i, j);
cout << "Swapped:\ti=" << i << ";\tj=" << j << ".\n";
cout << "swap() can be used to swap two real numbers:\n";
float num1=1.2, num2=3.4;
cout << "Original:\tnum1=" << num1 << ";\tnum2=" << num2 << ".\n";
swap(num1, num2);
cout << "Swapped:\tnum1=" << num1 << ";\tnum2=" << num2 << ".\n";
cout << "swap() can be used to swap two characters:\n";
char ch1='a', ch2='b';
cout << "Original:\tch1=" << ch1 << ";\tch2=" << ch2 << ".\n";
swap(ch1, ch2);
cout << "Swapped:\tch1=" << ch1 << ";\tch2=" << ch2 << ".\n";
return 0;
}
/* Output:
swap() can be used to swap two integers:
Original: i=1; j=2.
Swapped: i=2; j=1.
swap() can be used to swap two real numbers:
Original: num1=1.2; num2=3.4.
Swapped: num1=3.4; num2=1.2.
swap() can be used to swap two characters:
Original: ch1=a; ch2=b.
Swapped: ch1=b; ch2=a.
*/
// End of program
Example:
/************************************************************
Filename: queue.cpp
Author: Zhiwei Wang
Date: July, 1997
Description:
main() {
int i=0;
while (i != 4) {
cout << "You can build a queue of data type int, float, or
char\n";
cout << "1. integer\t2. float\t3. char \t4. quit\n";
cout << "Enter your choice: (Type 1, 2, 3, or 4)\n";
cin >> i;
if (i == 4) return 0;
switch (i) {
case 1:
queue<int> iq;
menu(iq);
break;
case 2:
queue<float> fq;
menu(fq);
break;
case 3:
queue<char> cq;
menu(cq);
break;
default:
cout << "You have to choose 1, 2, 3, or 4.\n";
}
}
return 0;
}
// End of Program
You can use a comma-separated list for more than one generic data types, as shown in
the example below:
/************************************************************
Filename: moretype.cpp
Author: Zhiwei Wang
Date: July, 1997
Description:
An example of multiple generic data types
************************************************************/
#include <iostream>
main() {
record<char*, int, double> person("John", 32, 3245.34);
person.display();
cout << endl;
record<int, char, char*> note(3, 'A', "Call me");
note.display();
return 0;
}
/* Output:
Item1: John
Item2: 32
Item3: 3245.34
Item1: 3
Item2: A
Item3: Call me
*/
// End of Program
7.18.20. Exceptions
Error codes returned from procedures do not convey much information
to
the calling procedure. It is usually a number that indicates the
cause
of failure. But in many situations, it would be very helpful if more
informaiton about the cause of failure is available to the caller.
A simple error code cannot fulfill this goal. A popular alternative
to
returning error code is to raise exceptions. Exceptions are run-time
anomalies that a program may detect. They indicate an abnormal
conditon
that should not be encountered.
Example:
NodeData Queue::Dequeue()
{
NodeData Temp;
if (IsEmpty())
throw EOQ();
ToHead();
Temp = Read();
Delete();
return Temp;
}
In the previous example, EOQ is a class defined inside class Queue by the following
statement:
class EOQ {};
The expression followed the throw keyword is an invocation of the constructor of
EOQ. This invocation creates an object of EOQ, which is thrown by the throw
statement.
The code that can throw exceptions should be enclosed in a try block. Following the try
block is a list of catch clauses.
Example
try {
Current = SearchQ.Dequeue();
// If we get here, we successfully dequeued a state from
// the Search Queue, so we must decrement the size of the
// Leaf List.
LeafList--;
}
catch (PriorityQueue::EOQ) {
NodesRemaining = FALSE;
cout << "\nThere is no solution to this Puzzle!" << endl;
break;
}
The general forms of try and catch statement are shown as follows:
try {
// try block
}
catch (type1 arg) {
// catch block
}
catch (type2 arg) {
//catch block
}
.
.
.
catch (typen arg) {
// catch block
}
When an exception is thrown, if its data type matchs the data type specified by a catch
statement, the exception will be
caught, and the corresponding catch statement will be executed. All the other catch
statements will be bypassed.
When an exception is caught, arg will receive it value.
Example:
#include <iostream>
try {
cout << "begin" << endl;
throw 100;
cout << "this will not be shown" << endl;
}
catch (int i) {
cout << "Caught an exceptionm, the value is: ";
cout << i << endl;
}
cout << "The End" << endl;
}
output:
begin
Caught an exceptionm, the value is: 100
The End
If you change the data type in the catch statement from int to a different type,
then the exception will not be caught and abnormal termination of the program will
occur.
Example:
#include <iostream>
main() {
cout << "Begin" << endl;
Ehandler(1);
Ehandler(0);
Ehandler(2);
return 0;
}
output:
Begin
Caught: 1
Caught: Value is zero..
Caught: 2
main() {
cout << "Begin" << endl;
Ehandler(0);
Ehandler(1);
Ehandler(2);
Ehandler(3);
return 0;
}
Output:
Begin
Caught: Value is zero.
Caught one.
Caught one.
Caught: 3
If necessary, you can restrict the types of exceptions a function can throw. The general
form of doing this is:
ret-type func-name(arg-list throw (type list) {
// function body
}
Example
#include <iostream>
main() {
cout << "Begin\n";
try {
Ehandler(0);
} catch (int i) {
cout << "Caught an integer\n";
} catch (char c) {
cout << "Caught a character\n";
} catch (float n) {
cout << "Caught a float\n";
} catch (char * str) {
cout << "Caught a string\n";
}
cout << "end" << endl;
}
Throwing any other types of exceptions will cause abnormal termination. If you don't
want to throw any exceptions, use an empty list.
Example
#include <iostream>
Note that the restriction applies only to the types of exceptions that are thrown back to
the calling function. Within a function, a try block can throw any exception as long as it
is caught within the function.
#include <iostream>
using namespace std;
void Ehandler(int i) throw () {
try {
switch (i) {
case 0:
throw "Value is zero.";
break;
case 1:
throw 'a';
break;
case 2:
throw 3,14;
break;
default:
throw i;
}
}
catch (int e) {
cout << "Caught: " << e << endl;
}
catch (char * e) {
cout << "Caught: " << e << endl;
}
catch (...) {
cout << "Caught one." << endl;
}
}
An exception can be re-thrown from within a catch block by calling throw with no
exception.
Example:
#include <iostream>
using namespace std;
void Ehandler(){
try {
throw "Hello";
}
catch (char *) {
cout << "Caught char * inside Ehandler.\n";
throw; // rethrow char *
}
}
main() {
cout << "Begin\n";
try {
Ehandler();
}
catch (char * ) {
cout << "Caught char * inside main\n";
}
cout << "end" << endl;
}
Exception handling is designed to provide a structured means by which your program
can handle abnormal events.
Example:
#include <iostream>
main() {
double i, j;
do {
cout << "Enter numerator (0 to stop): ";
cin >> i;
cout << "Enter denominator: ";
cin >> j;
divide(i, j);
} while (i != 0);
}