Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ Timesaving Techniques (2005) [eng].pdf
Скачиваний:
65
Добавлен:
16.08.2013
Размер:
8.35 Mб
Скачать

350 Technique 58: Converting the Case of a String

way to modify the individual elements of a container through a conversion function. This saves time because the algorithm has already been written, debugged, and optimized. It also saves time because you can easily extend your conversion functions without rewriting the basic algorithm.

Always make sure that you are using the most efficient code for your application up front. Rather than trying to implement your own algorithms to work with the Standard Template Library, choose to use the ones in the <algorithm> include file as they have been optimized for working with the STL collections.

Implementing the transform Function to Convert Strings

The transform algorithm of the Standard Template Library uses a function created by the user of the algorithm to convert each element of a container in some way. The following steps show you how to create a simple transform function to convert the case of a string, to either upperor lowercase. By looking at the technique and how the code is implemented, you will be able to see how to extend the functionality for your own uses in the future. In order to implement this function, we will need to implement a class which does the work of our transformation. The transform algorithm accepts two iterators and an object to do its work. Let’s take a look at exactly how this is implemented in your own code.

1. In the code editor of your choice, create a new file to hold the code for the source file of the technique.

In this example, the file is named ch58.cpp, although you can use whatever you choose. This file will contain the class definition for your automation object.

2. Type the code from Listing 58-1 into your file.

Better yet, copy the code from the source file on this book’s companion Web site.

LISTING 58-1: CONVERSION CODE FOR THE STL STRING CLASS

#include <string> #include <algorithm> #include <iostream> #include <vector> #include <ctype.h>

using namespace std;

//A function for converting a string to

//lowercase.

string convert_to_lowercase( const string& sIn )

{

//First, save a pointer to the function.

int (*pf)(int)=tolower;

//Next, convert the string. string sOut = sIn;

transform(sOut.begin(), sOut.end(),

sOut.begin(), pf);

return sOut;

}

//A function for converting a string to

//uppercase.

string convert_to_uppercase( const string& sIn )

{

//First, save a pointer to the function.

int (*pf)(int)=toupper;

//Next, convert the string. string sOut = sIn; transform(sOut.begin(), sOut.end(),

sOut.begin(), pf);

return sOut;

}

Testing the String Conversions 351

string strip_leading ( const string& sIn )

{

//Find the first non-white-space character.

int iPos = 0;

while ( iPos < sIn.length() && isspace ( sIn[iPos] ) )

iPos ++;

// Copy the rest of it. string sOut;

for ( int i=iPos; i<sIn.length(); ++i ) sOut += sIn[i];

return sOut;

}

string strip_trailing ( const string& sIn )

{

//Find the last non-white-space character.

int iPos = sIn.length()-1;

while ( iPos >= 0 && isspace( sIn[iPos]

) )

iPos --;

// Copy the rest of it. string sOut;

for ( int i=0; i<=iPos; ++i ) sOut += sIn[i];

return sOut;

}

//This is a utility class that will convert

//a string to lowercase.

class StringConvertToLowerCase

 

1

{

 

public:

string operator()(string s)

{

return convert_to_lower_case(s);

}

};

//This is a utility class that will strip

//leading AND trailing white space.

class StringStripSpace

{

public:

string operator()(string s)

{

return strip_leading(strip_ trailing(s));

}

};

This code implements all of the various possible transforms for the string class, and throws in several bonus methods for manipulating the strings (such as stripping the leading and trailing characters). In all cases, we will use the transform method to actually modify the strings or arrays. As the test driver in this technique illustrates, a single string is no more difficult to convert than is an entire string array. The important functionality here is the class we will be using to convert strings to lowercase, which is the StringConvertToLowerCase class shown at 1. The transform function uses this class to convert strings. As you can see, all of the work is done in a single method, the operator() method. This method is called by the transform algorithm to do its work, as we will see shortly.

Testing the String Conversions

After you create a class, you should create a test driver that not only ensures that your code is correct, but also shows people how to use your code.

The following list shows you how to create a test driver that illustrates various kinds of input from the user, and shows how the class is intended to be used.

1. In the code editor of your choice, reopen the source file to hold the code for your test program.

In this example, I named the test program ch58.cpp.

352 Technique 58: Converting the Case of a String

2. Type the code from Listing 58-2 into your file.

Better yet, copy the code from the source file on this book’s companion Web site.

LISTING 58-2: THE STRING CONVERSION TEST DRIVER

int main(int argc, char **argv)

{

vector<string> stringArray; if ( argc < 2 )

{

cout << “Usage: ch7_3 string1 [string2 string3...]” << endl;

cout << “Where: string[n] is the string to convert” << endl;

return -1;

}

// First, do them individually.

cout << “Individual Conversions: “ << endl;

for ( int i=1; i<argc; ++i )

{

cout << “Input String: “ << argv[i]

 

 

<< endl;

 

string sLower =

 

convert_to_lower_case( argv[i] );

 

cout << “Lowercase String: “ <<

 

sLower.c_str() << endl;

 

string sUpper =

 

convert_to_upper_case( argv[i] );

 

cout << “Uppercase String: “ <<

 

sUpper.c_str() << endl;

 

stringArray.insert(

}

stringArray.end(), argv[i] ); 4

//Now do the whole array. transform(stringArray.begin(),

stringArray.end(),

stringArray.begin(), StringConvertToLowerCase() );

//Print them out.

cout << endl << “Array Conversions: “ << endl;

vector<string>::iterator iter;

for ( iter = stringArray.begin(); iter != stringArray.end(); ++iter )

cout << “String: “ << (*iter).c_str() << endl;

cout << endl << “Individual String Whitespace Strip Test: “ << endl;

string whiteSpace = “ This is a test “;

string sNoWhite = strip_leading( whiteSpace );

cout << “Stripped String: [“ << sNoWhite.c_str() << “]” << endl;

sNoWhite = strip_trailing( whiteSpace ); cout << “Stripped String: [“ <<

sNoWhite.c_str() << “]” << endl;

transform(stringArray.begin(),

stringArray.end(),

stringArray.begin(), StringStripSpace() );

cout << endl << “Array of Strings Whitespace Strip Test: “ << endl;

for ( iter = stringArray.begin(); iter != stringArray.end(); ++iter )

cout << “String: [“ << (*iter).c_str() << “]” << endl;

return 0;

}

3. Save the source code in your code editor and close the editor application.

4. Compile the source code with your favorite compiler, on your favorite operating system.

5. Run the program on your favorite operating system.

If you have done everything right, you should see the output shown in Listing 58-3 in the console window.

Testing the String Conversions 353

LISTING 58-3: OUTPUT FROM THE STRING CONVERSION TEST

$ ./a.exe “ This is a test” “This is

 

2

another test

“ “ Final Test “

 

Individual Conversions:

3

Input String:

This is a test

 

 

Lowercase String:

this is a test

 

 

Uppercase String:

THIS IS A TEST

 

 

Input String: This is another test

 

 

Lowercase String: this is another test

 

 

Uppercase String: THIS IS ANOTHER TEST

 

 

Input String:

Final Test

 

 

Lowercase String:

final test

 

 

Uppercase String:

FINAL TEST

 

 

Array Conversions:

 

 

5

String:

this is a test

 

String: this is another test

 

String:

final test

 

 

 

Individual

String Whitespace Strip Test:

 

Stripped String: [This is a test

]

 

Stripped String: [

This is a test]

 

Array of Strings Whitespace Strip Test: String: [this is a test]

String: [this is another test] String: [final test]

The first line of the output is simply the executable name and the arguments to the program (shown

at

2). As you can see, we are passing in three

 

 

 

 

 

arguments. The various transformations are then

run on each of these arguments. First, we use the

individual utility functions (as shown at

 

3) to

convert each of the input strings. This

simply shows

 

 

 

that the functions are working properly. The strings are then added to an array (shown at 4 in Listing 58-2). The transform functions are then applied, converting each string to lowercase (shown in the output at 5). Finally, just to show how the transformation can be applied to any string, we use the white space removal functions to change the strings to have no leading or trailing white space.

Keep a library of utility classes around for all of your projects and you will find that you use them automatically — saving time and energy in solving little problems.

59 Implementing a

Serialization

Technique Interface

Save Time By

Understanding interfaces

Understanding serialization

Implementing a serialization interface

Testing the interface

Implementing interfaces can save you loads of time when you are doing the same thing over and over in your application, or even across applications. In addition, it collects all of the code for a given task in one

place, making it quick and easy to change the format of output files or the algorithm used for the functionality of the interface.

If you have ever used Java as a programming language, you’re probably already accustomed to interfaces. Simply put, an interface is a base class from which you can inherit that provides a given service. The C++ language supports interfaces, although they are slightly different in terms of syntax. Unlike a typical base class, interfaces are less concrete and do not generally allow the application to build upon them, but rather to use them to provide a specific service. In C++, an interface is a pure virtual base class that contains multiple pure virtual methods. A pure virtual method, unlike a regular virtual method, must be overridden by a derived class. For example, an interface might allow your class to print itself out, or save itself to a file, or even allocate its memory from some specialized form of hardware space. This technique shows how to implement an important concept — serialization — as an interface. The most important thing about interfaces, and the way in which they will save you the majority of time, is that if you inherit from an interface, you can pass your object to any function or method that works with objects that implement that interface. So, if you have a function that is used to save all sorts of objects, you can pass your object to the function so long as it implements the Save interface.

Essentially, serialization is the capability of an object to write itself to some form of persistent storage. The code that does the job tends to be the same from class to class; the data being written is what changes. Accordingly, serialization lends itself perfectly to the process of creating an interface.

There are two basic steps to implementing an interface in your class: