Standard Library Class string
In this chapter, you learned that you can build a String class (Figs. 11.911.11) that is better than the C-style, char * strings that C++ absorbed from C. You also learned that you can build an Array class (Figs. 11.611.8) that is better than the C-style, pointer-based arrays that C++ absorbed from C.
Building useful, reusable classes such as String and Array takes work. However, once such classes are tested and debugged, they can be reused by you, your colleagues, your company, many companies, an entire industry or even many industries (if they are placed in public or for-sale libraries). The designers of C++ did exactly that, building class string (which we have been using since Chapter 3) and class template vector (which we introduced in Chapter 7) into standard C++. These classes are available to anyone building applications with C++. As you will see in Chapter 23, Standard Template Library (STL), the C++ Standard Library provides several predefined class templates for use in your programs.
To close this chapter, we redo our String (Figs. 11.911.11) example, using the standard C++ string class. We rework our example to demonstrate similar functionality provided by standard class string. We also demonstrate three member functions of standard class stringempty, substr and atthat were not part of our String example. Function empty determines whether a string is empty, function substr returns a string that represents a portion of an existing string and function at returns the character at a specific index in a string (after checking that the index is in range). Chapter 18 presents class string in detail.
Standard Library Class string
The program of Fig. 11.15 reimplements the program of Fig. 11.11, using standard class string. As you will see in this example, class string provides all the functionality of our class String presented in Figs. 11.911.10. Class string is defined in header (line 7) and belongs to namespace std (line 8).
Figure 11.15. Standard Library class string.
(This item is displayed on pages 614 - 616 in the print version)
1 // Fig. 11.15: fig11_15.cpp 2 // Standard Library string class test program. 3 #include 4 using std::cout; 5 using std::endl; 6 7 #include 8 using std::string; 9 10 int main() 11 { 12 string s1( "happy" ); 13 string s2( " birthday" ); 14 string s3; 15 16 // test overloaded equality and relational operators 17 cout << "s1 is "" << s1 << ""; s2 is "" << s2 18 << ""; s3 is "" << s3 << '"' 19 << " The results of comparing s2 and s1:" 20 << " s2 == s1 yields " << ( s2 == s1 ? "true" : "false" ) 21 << " s2 != s1 yields " << ( s2 != s1 ? "true" : "false" ) 22 << " s2 > s1 yields " << ( s2 > s1 ? "true" : "false" ) 23 << " s2 < s1 yields " << ( s2 < s1 ? "true" : "false" ) 24 << " s2 >= s1 yields " << ( s2 >= s1 ? "true" : "false" ) 25 << " s2 <= s1 yields " << ( s2 <= s1 ? "true" : "false" ); 26 27 // test string member-function empty 28 cout << " Testing s3.empty():" << endl; 29 30 if ( s3.empty() ) 31 { 32 cout << "s3 is empty; assigning s1 to s3;" << endl; 33 s3 = s1; // assign s1 to s3 34 cout << "s3 is "" << s3 << """; 35 } // end if 36 37 // test overloaded string concatenation operator 38 cout << " s1 += s2 yields s1 = "; 39 s1 += s2; // test overloaded concatenation 40 cout << s1; 41 42 // test overloaded string concatenation operator with C-style string 43 cout << " s1 += " to you" yields" << endl; 44 s1 += " to you"; 45 cout << "s1 = " << s1 << " "; 46 47 // test string member function substr 48 cout << "The substring of s1 starting at location 0 for " 49 << "14 characters, s1.substr(0, 14), is: " 50 << s1.substr( 0, 14 ) << " "; 51 52 // test substr "to-end-of-string" option 53 cout << "The substring of s1 starting at " 54 << "location 15, s1.substr(15), is: " 55 << s1.substr( 15 ) << endl; 56 57 // test copy constructor 58 string *s4Ptr = new string( s1 ); 59 cout << " *s4Ptr = " << *s4Ptr << " "; 60 61 // test assignment (=) operator with self-assignment 62 cout << "assigning *s4Ptr to *s4Ptr" << endl; 63 *s4Ptr = *s4Ptr; 64 cout << "*s4Ptr = " << *s4Ptr << endl; 65 66 // test destructor 67 delete s4Ptr; 68 69 // test using subscript operator to create lvalue 70 s1[ 0 ] = 'H'; 71 s1[ 6 ] = 'B'; 72 cout << " s1 after s1[0] = 'H' and s1[6] = 'B' is: " 73 << s1 << " "; 74 75 // test subscript out of range with string member function "at" 76 cout << "Attempt to assign 'd' to s1.at( 30 ) yields:" << endl; 77 s1.at( 30 ) = 'd'; // ERROR: subscript out of range 78 return 0; 79 } // end main
|
Lines 1214 create three string objectss1 is initialized with the literal "happy", s2 is initialized with the literal " birthday" and s3 uses the default string constructor to create an empty string. Lines 1718 output these three objects, using cout and operator <<, which the string class designers overloaded to handle string objects. Then lines 1925 show the results of comparing s2 to s1 by using class string's overloaded equality and relational operators.
Our class String (Figs. 11.911.10) provided an overloaded operator! that tested a String to determine whether it was empty. Standard class string does not provide this functionality as an overloaded operator; instead, it provides member function empty, which we demonstrate on line 30. Member function empty returns true if the string is empty; otherwise, it returns false.
Line 33 demonstrates class string's overloaded assignment operator by assigning s1 to s3. Line 34 outputs s3 to demonstrate that the assignment worked correctly.
Line 39 demonstrates class string's overloaded += operator for string concatenation. In this case, the contents of s2 are appended to s1. Then line 40 outputs the resulting string that is stored in s1. Line 44 demonstrates that a C-style string literal can be appended to a string object by using operator +=. Line 45 displays the result.
Our class String (Figs. 11.911.10) provided overloaded operator() to obtain substrings. Standard class string does not provide this functionality as an overloaded operator; instead, it provides member function substr (lines 50 and 55). The call to substr in line 50 obtains a 14-character substring (specified by the second argument) of s1 starting at position 0 (specified by the first argument). The call to substr in line 55 obtains a substring starting from position 15 of s1. When the second argument is not specified, substr returns the remainder of the string on which it is called.
Line 58 dynamically allocates a string object and initializes it with a copy of s1. This results in a call to class string's copy constructor. Line 63 uses class string's overloaded = operator to demonstrate that it handles self-assignment properly.
Lines 7071 used class string's overloaded [] operator to create lvalues that enable new characters to replace existing characters in s1. Line 73 outputs the new value of s1. In our class String (Figs. 11.911.10), the overloaded [] operator performed bounds checking to determine whether the subscript it received as an argument was a valid subscript in the string. If the subscript was invalid, the operator printed an error message and terminated the program. Standard class string's overloaded [] operator does not perform any bounds checking. Therefore, the programmer must ensure that operations using standard class string's overloaded [] operator do not accidentally manipulate elements outside the bounds of the string. Standard class string does provide bounds checking in its member function at, which "throws an exception" if its argument is an invalid subscript. By default, this causes a C++ program to terminate.[6] If the subscript is valid, function at returns the character at the specified location as a modifiable lvalue or an unmodifiable lvalue (i.e., a const reference), depending on the context in which the call appears. Line 77 demonstrates a call to function at with an invalid subscript.
[6] Again, Chapter 16, Exception Handling, demonstrates how to "catch" such exceptions.