Useful Classes and Functions - II
The following topics are covered in this section:
Creating New Manipulators (Custom Manipulators)
In the previous chapter we dealt with how to overload << and >>. C++ also provides a way to create your own manipulators.
You can create your manipulators to work along with ‘cout’ (output stream object) or with ‘cin’ (input stream object). Let us consider an example of a manipulator dealing with ‘cout’. The syntax for creating a manipulator is:
ostream& name (ostream &str)
{
//code to be executed;
}
In the case of manipulators to be used with input stream, only one modification is necessary.
istream& name (istream &str)
{
//code to be executed;
}
Remember: You should return the stream at the end of your manipulator definition. Only then can you use your manipulator in cascaded operation.
#include <iostream.h>
ostream& divider (ostream &str)
{
str<<"--------------------------------"<<endl;
return str;
}
int main( )
{
int x;
cout<<divider<<"Enter an integer value : ";
cin>>x;
cout<<divider<<"The value you entered is : ";
cout<<x;
return 0;
}
The output is:
--------------------------------
Enter an integer value : 98
--------------------------------
The value you entered is : 98
In the above program we have created a new manipulator called ‘divider’. This will simply display a series of dashes on the screen as can be seen in the output. This manipulator can be used for objects belonging to ‘ostream’. Since ‘cout’ belongs to ‘ostream’, we can use this manipulator to operate only on output streams.
In a similar way you can also create manipulators to operate on input streams as well. The advantage of creating your own manipulators is that you can reduce on the amount of typing and make your code easier to understand.
Stream Formatting Member Functions:
The alternative to manipulators is to use the member functions available in streams. Manipulators can be used to perform all the stream-formatting that can be done using member functions.
Each stream has a set of format flags associated with it (just like what we have seen earlier). There are member functions available to either set/reset these format flags (the information is formatted depending on the setting of these flags).
The functions available are:
These functions can be called from streams using the dot operators (since they are all member functions). The setf( ) and unsetf( )functions are used to set and reset the format flags respectively. The list of format flags used are the same as those described for manipulators. The bitwise OR operator ( | ) can be used to set or reset more than one flag using setf( ) or unsetf( ).
There are two methods for creating and using strings. A character array terminated in a null character (‘\0’) is called a string but in new compilers you can make use of a class called ‘string’. There are a few reasons why you might prefer to use the existing string class instead of creating a character array. The problem with a character array is that many (in fact none) of the operators will work with character arrays. You cannot use ‘+’ and expect the two arrays to get added (adding in this case would mean concatenation of the two character arrays). You cannot use the assignment operator and assign a value to your character array. Many beginners make this fundamental mistake.
int main( )
{
char name[40];
name="John"; //wrong
cout<<name;
return 0;
}
It might seem as if the above coding is correct but if you compile this program you will get an error. The compiler will not accept such assignments but the following is correct:
int main( )
{
char name[40];
cin>>name;
cout<<name;
return 0;
}
We can obtain the input for a character array from the user and store it in the array ‘name’. This will work but assignment using the = operator will not work.
Most of the new compilers have a class called ‘string’. Since this is a class, many operators have already been overloaded such that they work effectively with string objects. Thus it would be better to make use of the string class in many instances. The string class is present in the header file string. The concept of namespaces will be explained later in this section. But for the time being just know that if you want to add headers according to the latest standards, then you should not make use of .h in the #include directive.
#include <iostream> // New style headers
#include <string>
using namespace std;
int main( )
{
string name;
name="John";
cout<<name;
return 0;
}
The output is:
John
There are many constructors available in the string class, which allows you to initialize the string in different ways. The main ones are (‘name’ is the string object that is created):
string name; //an empty string
string name("John"); //initialized to John
string name(another-string); //initialized to value of another-string
string name(5,’j’); //initialized to "jjjjj"
Again there are different ways to assign values to strings:
name = "John";
name = another–string;
For example:
int main( )
{
string s1("Jenny");
string s2;
s2=s1;
cout<<s2;
return 0;
}
s2 will now have the string "Jenny".
Similarly, you can even use the + operator on 2 strings. Consider the same program given above. If you write:
s2 = s1+s2;
The value in s2 will be: JennyJenny
Remember: The + operator (when operating on string objects) will concatenate the two strings.
Though you have created a string called ‘s1’, you can still access the individual characters of the string as well. You just need to use the index number for accessing particular characters. For example:
cout<<s1[1];
will give the output as:
e
In Jenny, ‘e’ is the second character and this is displayed. You might be led into thinking that if you want to change the first character of the string ‘s1’, all you need to do is type:
s1[0] = ‘k’;
The result will be compiler errors. You cannot change characters directly using the = operator. For this purpose the string class has a member function called
at(character-position)
The program would be as below:
int main( )
{
string s1("Jenny");
string s2;
s2=s1;
s2=s1+s2;
cout<<s2;
s1.at(0)='K';
cout<<endl<<s1;
return 0;
}
The output will be:
JennyJenny
Kenny
Remember: Strings are like character arrays and they also start from the index number 0 (not 1).
Comparison:
You can compare between two strings using the > or <. How do you think two strings are compared? See the following results:
e > bee -
True
Hello>hello - True
dear>bee - True
He>HE - False
From the above results it is clear that upper case letters are greater than corresponding lower case letters. An alphabet that comes later in A to Z is greater than one that comes before it. Comparison does not depend on the length of the strings.
To find the length of a string, you can make use of the length ( ) member function of the string class.
If s1 is a string object with the value of "Jenny", then
s1.length( )
Will return a value of 5.
Extracting strings:
You can extract a part of the string by using the substr ( ) function. The syntax is:
substr(position-from-where-you-want-to-start, number-of-characters-to-extract);
This function can be called only through a string object (because it is a member function of the class ‘string’).
int main( )
{
string s1("Jenny is a wonderful person");
cout<<s1.substr(6,4);
return 0;
}
The output is:
is a
Searching in Strings:
There are two functions for the purpose of searching for particular characters or strings within strings. These are the find (find) and reverse find (rfind) member functions. Both functions will return the position (an integer) of the place where the particular character/string is located.
Remember: The results that you get are always starting from 0. So if your result is 2, it actually means the 3rd character.
#include <iostream>
#include <string>
using namespace std;
int main( )
{
string s1("penny is a wonderful person");
cout<<endl<<s1.find("is");
cout<<endl<<s1.find('w');
cout<<endl<<s1.find('p');
cout<<endl<<s1.rfind('p');
}
The output is:
6
11
0
21
The first three results should be quite clear. The function find ( ) will start searching from the left side of your string object. But rfind ( ) will start from the right-end of the string object. Once rfind ( ) locates a match it will display the result by counting how many characters from the left the match was located.
Remember: find ( ) searches from the left and gives result by counting from left. rfind( ) searches from the right, but gives the resultant position by counting from left.
What if find ( ) or rfind ( ) don’t find a match? They’ll return some erroneous number (something that will be outside the length of the string itself!).
Go back to the Contents Page 2
Copyright © 2004 Sethu Subramanian All rights reserved.