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 //***********************************************************
/*************************************************************** 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 */
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 //************************************************************/
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 //********************************************************************
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 //**********************************************
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 //************************************************************
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
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;
}
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;
}
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.
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]%
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();
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 //***********************************************
/************************************************************ 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.
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 //*************************************************
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.
/************************************************************ 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 //***************************************************
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.
/********************************************************* 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 //****************************************************
/********************************************************* 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 //****************************************************
/********************************************************* 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 //****************************************************
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.
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
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
/************************************************************ 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
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
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 ProgramThis time, the program gives the desired output.
/************************************************************ 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; }
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";} };
/************************************************************ 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. */
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
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
template <class Ttype> class class-name{ ... }Once a generic class is declared, you create an object of that class using the following format:
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
/************************************************************ 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
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;
// 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.
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
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
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;
}
}
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";
}
}