Sunteți pe pagina 1din 42

7.

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

• 7.18.9. THE C++ I/O SYSTEM


o 7.18.9.1. C++ I/O Basics
o 7.18.9.2. Formatted I/O
o 7.18.9.3. File I/O
• 7.18.10. CLASSES AND OBJECTS
o 7.18.10.1. Classes and Objects
o 7.18.10.2. Encapsulation and Information Hiding
o 7.18.10.3. Constructors and Destructors
• 7.18.11. VARIABLE SCOPE AND LIFETIME
o 7.18.11.1 Namespaces
o 7.18.11.2 Variable Scope
o 7.18.11.3 Variable Lifetime
• 7.18.12. FUNCTION OVERLOADING
o 7.18.12.1. Polymorphism
o 7.18.12.2. Ambiguity
• 7.18.13. OPERATOR OVERLOADING
o 7.18.13.1. Operator Overloading Using a Member function
o 7.18.13.2. Operator Overloading using a Friend Function
o 7.18.13.3. Restrictions in Operator Overloading
• 7.18.14. INHERITANCE
o 7.18.14.1. Base Classes and Derived Classes
o 7.18.14.2. Member Access
o 7.18.14.3. Multiple Inheritance and Inheriting Multiple Base classes
• 7.18.15. ARRAYS OF OBJECTS
o 7.18.15.1 Arrays of Objects
o 7.18.15.2. Initialization without Parameters
o 7.18.15.3. Initialization with One Parameter
o 7.18.15.4. Initialization with More than One Parameter
• 7.18.16. POINTERS TO OBJECTS
o 7.18.16.1. Pointers to Objects
o 7.18.16.2. Pointer Arithmetic
o 7.18.16.3. The 'this' Pointer
o 7.18.16.4. Pointers to Classes Members
• 7.18.17. REFERENCES
o 7.18.17.1. Pass Argument by Value
o 7.18.17.2. Pass Argument by References
o 7.18.17.3. Reference Arguments
• 7.18.18. VIRTUAL FUNCTIONS
o 7.18.18.1. Polymorphic Classes and Virtual Functions
o 7.18.18.2. Virtual Function Invocation
o 7.18.18.3. Pure Virtual Functions and Abstract Classes
• 7.18.19. TEMPLATES
o 7.18.19.1. Generic Functions
o 7.18.19.2. Generic Classes
o 7.18.19.3. Examples with More than One Generic Data Types
• 7.18.20. EXCEPTIONS
o 7.18.20.1.The throw Statement
o 7.18.20.2 The try Statement
o 7.18.20.3 Caught all Exceptions
o 7.18.20.4 Restricting Exceptions
o 7.18.29.5 Rethrowing an Exception

7.18 C/C++ (Part 2)


C++ was first invented by Bjarne Stroustrup in 1980 at Bell Laboratories in Murray
Hill, New Jersey. He initially called it "C with Classes." However, in 1983 the name
was changed to C++. C++ is a superset of C. As a popular programming language, C
has many excellent features. However, once a program exceeds 25,000 to 100,000 lines
of code, it becomes too difficult to be comprehended as a whole. The purpose of C++ is
to overcome this limit and provide a better way to manage larger, more complex
programs, by using object oriented programming (OOP).

7.18.9. THE C++ I/O SYSTEM

7.18.9.1. C++ I/O Basics

When a C++ program is running, the following four built-in streams are automatically
opened:

Stream Meaning Default Device Corresponding C stream


cin standard input keyboard stdin
cout standard output screen stdout
cerr standard error output screen stderr
clog buffered version of cerr screen

The following is an example of using simple I/O streams:

Example

/*********************************************************
*
* FILE NAME: basics.cpp *
* AUTHOR: Zhiwei Wang *
* DATE: May. 1997 *
* DESCRIPTION: An example for simple I/O stream *
***********************************************************/
#include <iostream>

using namespace std;

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
//***********************************************************

7.18.9.2. Formatted I/O

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>

using namespace std;

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.

Some manipulators require parameters. To access manipulators that take parameters,


you have to include <iomanip.h> in your program. The following is an example of
using manipulators to format the output.

/*****************************************************************
FILE NAME: example2.cpp
AUTHOR: Zhiwei Wang
DATE: May. 1998
DESCRIPTION:
An example demonstrating how to use the manipulators.
*****************************************************************/
#include <iostream>
#include <iomanip>

using namespace std;


main()
{
int i=100;
double pi = 3.1415926535;

cout << i << endl;


cout << hex << i << endl;

cout << pi << endl;


cout << setfill('0') << setw(10) << setprecision(3) << pi << endl;

return 0;
}

/* Output:
100
64
3.14159
0000003.14
*/

7.18.9.3. File I/O

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.

stream name stream type


ifstream input
ofstream output
fstream input and output
To open a file, you create a stream and then call the member function open().

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>

using namespace std;


main(){
ifstream in;
char filename[20];
cout << "Enter the file name to read from: ";
cin >> filename;
in.open(filename);
if (!in) {
cout << "Input file cannot be opened.\n";
return(1);
}
char str[80];
while (!in.eof()) {
in >> str;
cout << str << " ";
strcpy(str, "");
}
cout << "\n";
in.close();
return (0);
}

//END OF PROGRAM
//************************************************************/

7.18.10. CLASSES AND OBJECTS

7.18.10.1. Classes and Objects

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.

A class name can be used as a type specifier to declare objects. An


object is a specific instance of a class. The following code declares
three objects a, b, and c as instances of the vector class:

vector a, b, c;

Let us examine a complete program to make the preceding explanation


clearer.

Example

/*********************************************************
Filename: sum.cpp Date: April 4, 1997
Author: Zhiwei Wang
Student Number:
Description: This program calculates the sum of two vectors.
**********************************************************/
#include <iostream>

using namespace std;

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

Information hiding refers to the control of access levels of members


of a class. This is done by using the three access_specifiers: public,
private, and protected. A class member specified as 'public' is
accessible from outside the class, while a 'private' member can be
accessed only by other members of the same class, or a friend
function. 'Protected' specifier is similar to 'private' as long
as derived classes are not involved. We will discuss 'friend
functions' and 'Derived classes' later.

Example:

/************************************************************
Filename: classes.cpp
Author: Zhiwei Wang
Date: May, 1997
Description: A simple class example
************************************************************/
#include <iostream>

using namespace std;

class person { // A simple class


int hour;
int rate;

public:
int income(void); // with two methods
void initialize(int, int);
};

int person::income(void) //Income of a person


{
return hour * rate;
}

void person::initialize(int init_hour, int init_rate)


{
hour = init_hour;
rate = init_rate;
}

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
//**********************************************

7.18.10.3. Constructors and Destructors


A function declared inside a class is a member function. Member
functions have full access to all members of the class.
A constructor is a special member function which has the same name as
the class. Constructors are used to initialize the class and are
automatically called when the objects are created. The complement of
the constructor is the destructor. A destructor name begins with a
tilde (~) character followed by the name of the class. When an object
is destroyed, its destructor is automatically called. Destructors are
needed because in many cases, some actions should be taken when an
abject is destroyed. For example, memory spaces need to be freed, or
an opened file need to be closed. Neither constructor nor destructor
can return any value, so there is no return type specified for them.

Example:

/************************************************************
Filename: structor.cpp
Author: Zhiwei Wang
Date: May, 1997
Description: A simple class example with constructor and
destructor.
************************************************************/
#include <iostream>
using namespace std;

class person { // A simple class


int hour;
int rate;

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";
}

int person::income(void) //Income of a person


{
return hour * rate;
}

void person::initialize(int init_hour, int init_rate)


{
hour = init_hour;
rate = init_rate;
}

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. Variable Scope and Lifetime

7.18.11.1. Namespaces

A namespace is a mechanism by which the program can create a named


scope.
A namespace definition consists of the word namespace, then an
identifier, and the the body of the namespace.

Example:
// in header file cstdlib:

namespace std
{
...
int abs(int);
...
}

Identifiers declared within the namespace body are said to


have namespce scope. They cannot be accessed outside the
body except by using one of the following methods:

1. using the name of the namespace, the scope resolution operator,


and the indentifier.
int a, b;
a = std::abs(b);

2. using the 'using declaration'


using std::abs;

3. using a 'using directive'


using namespace std;

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:

hercules[1]% CC hiusingname.cpp -LANG:std

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

7.18.11.2. Variable Scope

Scope refers to the region of program code where it is legal to


reference an identifier.

Class scope: The scope of class members is within the classe (struct,
union)

local: The scope of an dentifiers declared inside a block starts from


the point of the declaration and ends at the end of the block.

namespace scope: The scope of identifiers declared inside a namespace


is within the namespace.

global scope: The scope of an identifier declared outside all


functions and classes have the global scope.

Example:

#include <iostream>

using namespace std;

int num = 0; // global num


namespace myNamespace {
int num = 1; // num in a namespace
}

void myFunction(int num);


void myFunction2();
void myFunction3();

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 myFunction(int num) {


num = 9;
cout << num << endl;
}

void myFunction3() {
cout << num << endl;
}

void myFunction2() {
int num = 4;
cout << num << endl;
}

7.18.11.3. Lifetime of a Variable

The lifetime of a variable refers to the period of time during program


execution when an identifier actually has memory allocated to it.
An automatic variable is one whose storage is allocated at the block
entry and deallocated at the block exit. A static variable is one
whose storage remains allocated for the duration of the entire
program. All global variables are static variables. By default,
variables declared within a block are automatic variables. However,
you can use 'static' to declare a static local variable.

Static class members


If you declare a static variable in a class, all objects will share
the same variable.
Example:
#include <iostream>

using namespace std;

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

Member functions may also be declared as static. There are several


restrictions placed onstatic member functions:

They may only access other static members of the class.


static member functions do not have a 'this' pointer.
There cannot be a static and a non-static version of the same
function.
Example
#include <iostream>

using namespace std;


class myClass {
static int share;
int num;
public:
static int getShare() {return share;}
int getNum() {return num;}
static void setShare(int a) { share = a; }
void setNum(int a) { num = a;}
};

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. FUNCTION OVERLOADING

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>

using namespace std;

int f(float); // This function triples a float and returns int


int f(int); // This function returns the same integer
float f(float, float); // This function averages two floats

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

int f(int in_value) // This returns the same value


{
return in_value;
}

int f(float in_value) // Triples a float & return int


{
return (int)(3.0 * in_value);
}

float f(float in1, float in2) // This averages two floats


{
return (in1 + in2)/2.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.

Let us make a small change in the program overload.cpp'. Instead of


calling function 'f()' using the variables 'num' and 'num2', we use
their values directly. i.e. we replace the lines

int num = 12;


float num2 =12.0;
cout << "The number is " << f(num) << "\n";
cout << "3 times 12 is " << f(num2) << "\n";
with
cout << "The number is " << f(12) << "\n";
cout << "3 times 12 is " << f(12.0) << "\n";
Compile the altered program and you will get the following:
mercury[208]% CC example2.cpp
"example2.cpp", line 16: error(3389): more than one instance of
overloaded
function "f" matches the argument list:
function "f(float)"
function "f(int)"
cout << "3 times 12 is " << f(12.0) << "\n";

error detected in the compilation of "example2.cpp".


mercury[209]%

7.18.13. OPERATOR OVERLOADING

7.18.13.1. Operator Overloading Using a Member function

Many operators can be overloaded by creating operator functions.


Operator functions can be either members or non members of the class
that the operator will operate on. The format to create a member
operator function is:
ret-type class-name::operator#(arg-list)
{
// operation definition
}
where ret-type is the data type of the object returned by the
operator. The # is a placeholder which will be replaced by the symbol
of the operator. If you are overloading a unary operator, arg-list
will be empty, if you are overloading a binary operator, arg-list will
have one parameter, etc. Let us define a vector class and overload the
+ operator:

Example

/************************************************************
Filename: opover.cpp
Author: Zhiwei Wang
Date: July, 1997
Description:
overload operators using member functions.
************************************************************/
#include <iostream>

using namespace std;


class vector {
float x, y;
public:
vector(){};
vector(float a, float b) {x=a; y=b;}
void display() {cout << "x=" << x << ", y=" << y << endl;}
vector operator+(vector v);
float operator*(vector v);
};

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

/* The output of the program is:

vector 1 is: x=19, y=97


vector 2 is: x=7, y=11
The sum of the two vector is: x=26, y=108
The inner product of the two vector is: 1200
*/
// End of Program
//************************************************
Note that the overloaded '+' operator returns a vector, this makes the
statement

(f1+f2).display();

possible.

7.18.13.2. Operator Overloading using a Friend Function

Operators can be overloaded using friend functions. When use a friend


function to overload a unary operator, the function has one parameter;
to overload a binary operator, two parameters; etc.

The following program rewrites the preceding example using friends to


overload operators. Note that the main() function does not change.
/************************************************************
Filename: opover2.cpp
Author: Zhiwei Wang
Date: July, 1997
Description:
overload operators using friend functions
************************************************************/
#include <iostream>

using namespace std;

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

vector operator+(vector v1, vector v2) {


vector temp;
temp.x = v1.x + v2.x;
temp.y = v1.y + v2.y;
return temp;
}

float operator*(vector v1, vector v2) {


return (v1.x * v2.x + v1.y * v2.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 2 vectors is: ";
(f1+f2).display();
cout << "The inner product of the two vector is: "
<< f1 * f2 << endl;
return 0;
}
// End of Program
//***********************************************

7.18.13.3. Restrictions in Operator Overloading

Technically one can define any activities inside an operator function.


The short program gives an example.
/************************************************************
Filename: unexpected.cpp
Author: Zhiwei Wang
Date: July, 1997
Description:
************************************************************/
#include <iostream>

using namespace std;


class vector {
float x, y;
public:
vector(){};
vector(float a, float b) {x=a; y=b;}
void display() {cout << "x=" << x << ", y=" << y << endl;}
vector operator+(vector v);
};

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.

There are some restrictions that apply to operation overloading.

• You cannot alter the precedence of the operator;


• You cannot change the number of operands of the operator;
• The operators list below cannot be overloaded:
. :: .* ?

7.18.14. INHERITANCE

7.18.14.1. Base Classes and Derived Classes

Inheritance is one of the cornerstones of object-oriented programming.


It allows the members of one class to be used as if they were members
of a second class. Using inheritance, you create a base class that
defines members common to a set of classes, and then create derived
classes to inherit the base class. The members of the base class will
become the members of the derived classes. Let us examine an example:

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;

// base class definition


class measure_2d {
protected:
int length, width;
public:
void set (int a, int b) {length=a; width=b;}
void display() { cout << "length=" << length << "\nwidth=" << width
<< "\n";}
int area() { return length*width;}
};

// derived class definition


class measure_3d : public measure_2d {
int height;
public:
measure_3d (int a) {height=a;}
void display_height() { cout << "height=" << height << "\n";}
int volume() { return length * width * height;}
};

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

/* 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
//*************************************************

7.18.14.2. member Access

As we have seen in the example, the general form to define a class to


inherit base class is:
class derived-class-name:access base-class-name {
// body of class
};
where 'access' is the base class access specifier, which should be
either public, private, or protected. If no access specifier is
explicitly presented, the default one will be assumed. If the derived
class is a class, the default access specifier is private, If the
derived class is struct, it is public.

Let us examine what happens when the access specifier is public,


private, or protected respectively. When the specifier is public, all
public members of the base class become public members of the derived
class, all protected members of the base class become protected
members of the derived class, but all private members remain private
to the base class and are not accessible by the members of the derived
class.

Let us comment out the keyword 'protected' in the definition of class


measure_2d in the previous program '2d3d.cpp'. By default, 'length'
and 'width' will be private to the base class measure_2d. The new
program is as below:

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>

using namespace std;

// base class definition


class measure_2d {
// protected:
int length, width; // length and width are private now by default
public:
void set (int a, int b) {length=a; width=b;}
void display() { cout << "length=" << length << "\nwidth=" << width
<< "\n";}
int area() { return length*width;}
};

// derived class definition


class measure_3d : public measure_2d {
int height;
public:
measure_3d (int a) {height=a;}
void display_height() { cout << "height=" << height << "\n";}
int volume() { return length * width * height;}
// error here: length and width is private to the base
// class and cannot be access here by a member of the
// derived class.
};

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>

using namespace std;

// base class definition


class measure_2d {
protected:
int length, width;
public:
void set (int a, int b) {length=a; width=b;}
void display() { cout << "length=" << length << "\nwidth=" << width
<< "\n";}
int area() { return length*width;}
};

// derived class definition


class measure_3d : private measure_2d {
int height;
public:
measure_3d (int a) {height=a;}
void display_height() { cout << "height=" << height << "\n";}
int volume() { return length * width * height;}
};

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
//****************************************************

The following is what we get when we compile the altered program:


mercury[18]% CC 2d3d_b.cpp
"2d3d_b.cpp", line 31: error(3346): function "measure_2d::set" is
inaccessible
box.set(2, 4);
^
"2d3d_b.cpp", line 32: error(3346): function "measure_2d::display" is
inaccessible
box.display();
^
"2d3d_b.cpp", line 33: error(3346): function "measure_2d::area" is
inaccessible
cout << "The area of the box is " << box.area() << "\n";
^
3 errors detected in the compilation of "2d3d_b.cpp".
When the access specifier is 'protected', all public and protected members of the base
class become protected members of the derived class. Protected members are similar to
private members in that they are not accessible to other non-members, but are different
from private members when they are inherited: if the base class is inherited as protected
or public, all protected members of the base class become protected members of the
derived class.

7.18.14.3. Multiple Inheritance and Inheriting Multiple Base classes

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>

using namespace std;

class measure_l { // base class


protected:
int length;
public:
void displayl() { cout << "length=" << length << "\n";}
};

class measure_w { // base class


protected:
int width;
public:
void displayw() { cout << "width=" << width << "\n";}
};

// measure_2d inherits two classes, an example of inheriting


// multiple classes
class measure_2d: public measure_l, public measure_w {
public:
void set (int a, int b) {length=a; width=b;}
void display() { cout << "length=" << length << "\nwidth=" << width
<< "\n";}
int area() { return length*width;}
};

// measure_3d inherits a derived class, an example of


// multiple inheritance
class measure_3d : public measure_2d {
int height;
public:
measure_3d (int a) {height=a;}
void display_height() { cout << "height=" << height << "\n";}
int volume() { return length * width * height;}
};

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
//***************************************************

7.18.15. ARRAYS OF OBJECTS

7.18.15.1 Arrays of Objects

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.

7.18.15.2. Initialization without Parameters

The following example declares an array of object 'vector_1'.


/*********************************************************
Filename: vector1.cpp
Description:
**********************************************************/
#include <iostream>

using namespace std;

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
//****************************************************

7.18.15.3. Initialization with One Parameter

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>

using namespace std;

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
//****************************************************

7.18.15.4. Initialization with More than One Parameter

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>

using namespace std;

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
//****************************************************

7.18.16. POINTERS TO OBJECTS

7.18.16.1. Pointers to Objects

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>

using namespace std;

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.

7.18.16.2. Pointer Arithmetic

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.

7.18.16.3. The 'this' Pointer

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>

using namespace std;

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

7.18.16.4. Pointers to Classes Members

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>

using namespace std;

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.

7.18.17.1. Pass Argument by Value

In general, when an argument is passed to a function, the value of the argument is


copied to the 'formal parameter'. Any changes to the formal parameter has no effect on
the argument. This is called 'pass by value'. The following program illustrates this. It
attempts in vain to swap the value of two variables.
/************************************************************
Filename: swap1.cpp
Author: Zhiwei Wang
Date: July, 1997
Description:
This program illustrates that 'call by value' will not
change the value of the original arguments
************************************************************/
#include <iostream>

using namespace std;

void swap(int i, int j);

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

void swap(int i, int j){


int temp;
temp = i;
i = j;
j = temp;
}
/* Output:
a = 1 b = 2
After wrong swap:
a = 1 b = 2
*/
// End of Program

7.18.17.2. Pass Argument by References

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:

void swap(int *i, int *j){


int temp;
temp = *i;
*i = *j;
*j = temp;
}
Accordingly, the prototype of the function should be changed to:

void swap(int *i, int *j);

The following is the revised program and its out put.

/************************************************************
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;

void swap(int *i, int *j);

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

void swap(int *i, int *j){


int temp;
temp = *i;
*i = *j;
*j = temp;
}
/* Output:
a = 1 b = 2
After swap:
a = 2 b = 1
*/
// End of Program
This time, the program gives the desired output.

7.18.17.3 Reference Arguments

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>

using namespace std;

void swap(int &i, int &j);

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

void swap(int &i, int &j){


int temp;
temp = i;
i = j;
j = temp;
}

7.18.18. VIRTUAL FUNCTIONS

7.18.18.1. Polymorphic Classes and Virtual Functions

A polymorphic class is a class that includes a virtual function. A virtual function is a


special member function that is declared as virtual in a base class and re-defined
(called overridden) in derived classes. In the following example, 'person' is a
polymorphic class, which includes a virtual function greeting(). The class 'chinese'
inherits 'person' and overrides the virtual function greeting().

Example

class person {
public:
virtual void greeting() { cout << "Hello!\n";}
};

class chinese : public person { // greeting() is re-defined


public:
void greeting() { cout << "Ni Hao! I am a Chinese\n";}
};

7.18.18.2. Virtual Function Invocation


Virtual functions are used to accomplish run-time polymorphism, which means using
same interface for different methods. To do this, you need to invoke virtual functions
through a pointer to a particular class type. The program below is an illustration.
/************************************************************
Filename: virtual.cpp
Author: Zhiwei Wang
Date: July, 1997
Description: This program illustrates how to use virtual functions.
************************************************************/
#include <iostream>

using namespace std;

class person {
public:
virtual void greeting() { cout << "Hello!\n";}
};

class woman : public person { // greeting() is not overridden

class man : public person { // greeting() is overridden


public:
void greeting() { cout << "Hello! Lady first.\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.
*/

7.18.18.3. Pure Virtual Functions and Abstract Classes

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:

virtual type function_name(parameter-list) = 0;

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>

using namespace std;

class person { // 'person' is an abstract class


public:
virtual void greeting() = 0; // 'greeting()' is now a pure
//virtual function
};

class woman : public person { // greeting() must be overridden


public:
void greeting() { cout << "Hello!\n";}
};

class man : public person {


public:
void greeting() { cout << "Hello! Lady first.\n";}
};

main(){
// Abstract class cannot be used to create object 'b'.
// so comments out the following line
// person *p, b;

// However, abstract class can be used to create a pointer


// to it.

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>

using namespace std;

// 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

7.18.19.2. Generic Classes


The general form to declare a generic class is:
template <class Ttype> class class-name{
...
}
Once a generic class is declared, you create an object of that class using the following
format:
class-name <type> variable-name;

Example:

/************************************************************
Filename: queue.cpp
Author: Zhiwei Wang
Date: July, 1997
Description:

This program gives an example of using generic classes


and generic functions. The program implements a queue
on an array. The class 'queue' is a generic class.
You can use if for a queue of integers, 'float's, characters, etc.
The member function 'enqueue()' adds an item to the queue,
the function 'dequeue()' takes an item from the queue,
and the function 'showqueue()' display the queue.
'menu' is a generic function. It can be used for a
queue of integer items, 'float' items, 'char' items, etc.
************************************************************/
#include <iostream>

using namespace std;

const int SIZE = 100;

template <class QType> class queue {


QType q[SIZE];
int head, tail, count;
public:
queue();
QType item;
void enqueue(QType i);
QType dequeue();
void showqueue();
};

template <class QType> queue<QType>::queue() {


head = 0;
tail = 0;
count = 0;
cout << "Queue created.\n";
}

template <class QType> void queue<QType>::enqueue(QType i) {


if (count == SIZE) {
cout << "Queue is full.\n";
return;
}
q[tail++] = i;
count++;
tail %= SIZE;
}
template <class QType> QType queue<QType>::dequeue() {
if (count == 0) {
cout << "Queue is empty.\n";
return 0;
}
int temp;
temp = head;
head = (head+1)%SIZE;
count--;
return q[temp];
}

template <class QType> void queue<QType>::showqueue() {


if (count == 0) {
cout << "Queue is empty.\n";
return;
}
int temp = head;
for (int i=0; i<count; i++) {
cout << q[temp] << ";";
temp = (temp+1)%SIZE;
}
}

template <class QT> void menu(QT q) {


int choice = 0;
while (choice != 4) {
cout << "What do you want to do? Type number 1, 2, 3, or 4.\n";
cout << "1. add an item to the queue.\n";
cout << "2. take an item from the queue.\n";
cout << "3. display the queue.\n";
cout << "4. quit.\n";
cin >> choice;
if (choice == 4) return;
switch (choice) {
case 1:
cout << "Enter an item, please: ";
cin >> q.item;
q.enqueue(q.item);
cout << "\nItem enterred.\n";
break;
case 2:
cout << "The item to be served is: " << q.dequeue() << endl;
cout << "\nDone.\n";
break;
case 3:
cout << "The queue is:\n";
q.showqueue();
break;
default:
cout << "Please type 1, 2, 3, or 4\n";
}
}
}

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

7.18.19.3. Examples with More than One Generic Data Types

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>

using namespace std;

template <class Type1, class Type2, class Type3> class record {


Type1 name;
Type2 value;
Type3 info;
public:
record(Type1 a, Type2 b, Type3 c) {name=a; value=b; info=c;}
void display();
};

template <class Type1, class Type2, class Type3>


void record<Type1, Type2, Type3>::display() {
cout << "Item1:\t" << name << endl;
cout << "Item2:\t" << value << endl;
cout << "Item3:\t" << info << endl;
}

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.

7.18.20.1. The throw Statement

In C++, an exception is raised using a throw expression, which is composed of the


keyword
throw followed by an expression.

Example:
NodeData Queue::Dequeue()
{
NodeData Temp;

// Since "End of File" is an expected condition for a Queue, we


// must do something to signal EOF. So, we use the Catch/Throw
// mechanism in C++, and modify the exception name to reflect that
// this is a Queue.

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.

7.18.20.2. The try 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>

using namespace std;


main() {

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>

using namespace std;


void Ehandler(int i) {
try {
if (i==0)
throw "Value is zero..";
else
throw i;
}
catch (int e) {
cout << "Caught: " << e << endl;
}
catch (char *str) {
cout << "Caught: " << str << endl;
}
}

main() {
cout << "Begin" << endl;

Ehandler(1);
Ehandler(0);
Ehandler(2);

return 0;
}

output:
Begin
Caught: 1
Caught: Value is zero..
Caught: 2

7.18.20.3. Caught all Exceptions

Example: Using Multiple catch Statements


#include <iostream>
using namespace std;
void Ehandler(int i) {
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;
}
}

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

7.18.20.4. Restricting Exceptions

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>

using namespace std;


void Ehandler(int i) throw (int, char, float, char *) {
switch (i) {
case 0:
throw "Value is zero.";
break;
case 1:
throw 'a';
break;
case 2:
throw 3.14;
break;
default:
throw i;
}
}

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>

using namespace std;


// This function can throw no exception
void Ehandler(int i) throw () {
switch (i) {
case 0:
throw "Value is zero.";
break;
case 1:
throw 'a';
break;
case 2:
throw 3.14;
break;
default:
throw i;
}
}

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

7.18.20.5. Rethrowing an Exception

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>

using namespace std;

void divide(double a, double b);

main() {
double i, j;
do {
cout << "Enter numerator (0 to stop): ";
cin >> i;
cout << "Enter denominator: ";
cin >> j;
divide(i, j);
} while (i != 0);
}

void divide(double a, double b) {


try {
if (!b) throw b;
cout << "Result: " << a/b << endl;
} catch (double b) {
cout << "Can't divide by zero.\n";
}
}

S-ar putea să vă placă și