8.3. The C++ string Class

Time: 00:03:17 | Download: Large, Large (CC) Small | Streaming, Streaming (CC) | Slides: PDF, PPTX
Review

Following a practice common in object-oriented programming languages, C++ provides a more-capable string implementation as a string class. Developers often use strings, regardless of how a language implements them, as a fundamental type. The C++ string class is well-designed, providing numerous customary operations, implemented as functions or operators. Introducing the string class before classes in general allows the examples in that chapter to use strings as class members, making the examples more realistic and useful. A brief object-oriented preview or review is sufficient for introducing the string class.

Object-Oriented Preview

Leveraging two previously described features helps introduce the C++ string class. Like the I/O system, C++ declares the string class in a header file that client files include. Clients can use either the using statement or the scope resolution operator. Like structures, a class is a programmer-defined data type that programs instantiate to create an object that stores program data. Programs can create objects on the stack or on the heap, and access the object's features with the dot or arrow operator. The most profound difference between classes and structures is that classes typically have functions, while structures generally do not. Some of the class functions run automatically, but programmers explicitly call most of them.

#include <string>
using namespace std;
#include <string>
Accesses the string class features.
string s1;
std::string s1;
Creates an empty string object (variable) named s1.
string s2("Hello, World!");
string s2 = "Hello, World!";
std::string s2("Hello, World!");
std::string s2 = "Hello, World!"
Creates a string object s2 by copying the C-string.
string s3(s2);
string s3 = s2;
std::string s3(s2);
std::string s3 = s2;
Creates a string object s2 by copying s2.
Creating string objects. Numerous examples throughout the text define and use variables. Creating or instantiating an object is the same process, but it generally describes the creation of structured data from a class or structure. When programs instantiate class objects, they often automatically run specialized functions called constructors that initialize the object (e.g., by copying data into the object). These examples follow the standard variable-definition syntax, but the data type is a class, and the variable is an object created on the stack and initialized by a constructor function.

The string class hides the complexity of its operations, effectively separating its interface from its implementation. So, programmers see what the class can do but not how it does it. For example, the string class provides a significant advantage over C-strings: once created, a C-string has a maximum length beyond which it cannot grow. The size of the character array that stores the C-string limits its length. Alternatively, string objects manage their memory, making them dynamic and allowing them to grow automatically as needed. When a string needs to grow, it allocates a new, larger array with new, copies the existing data into the new array, and deallocates the old array with delete. The class hides these operations from programs and programmers alike.

Calling string Functions: The Dot And Arrow Operators

#include <iostream>
#include <string>
using namespace std;

int main()
{
    string s1;									// stack objects
    string s2("hello");
    string s3(s2);
    string* s4 = new string("the quick brown fox jumps over the lazy dog");	// heap object

    cout << s1 << endl;								// the string is empty, prints the newline
    cout << s2 << endl;								// hello
    cout << s3 << endl;								// hello
    cout << *s4 << endl;							// the quick brown fox jumps over the lazy dog

    cout << s1.size() << " " << s1.length() << " " << s1.capacity() << endl;	// 0 0 15
    cout << s2.size() << " " << s2.length() << " " << s2.capacity() << endl;	// 5 5 15
    cout << s3.size() << " " << s3.length() << " " << s3.capacity() << endl;	// 5 5 15
    cout << s4->size() << " " << s4->length() << " " << s4->capacity() << endl;	// 43 43 47

    return 0;
}

(a)

A picture of a string object that stores the characters 'hello' but has a total capacity of 15. The last ten characters are empty in the sense that no known data is stored there - they contain whatever was in that memory location when the string was created.

(b) - s2 and s3

Fundamental string operators and functions. The ANSI C++ standard does not specify the implementation details for the string class, and differences between compilers are easy to find. For example, the compiler used for this example creates strings with a minimum capacity of 15 characters (leaving space for additional characters before the string must grow), but not all string classes share this behavior.
  1. The program constructs four string objects: s1 through s4. Three string functions, size, length, and capacity, illustrate objects calling their functions with the dot and arrow operators. The size and length functions are synonyms - they are different names for the same operation: the number of characters currently stored in a string object. capacity is the maximum number of characters the string can store without growing. cout, endl, and inserter operator, <<, recognize string objects and operate as expected. The program must dereference s4 to print it because it is a string pointer.
  2. string objects manage their data as character arrays. s2 and s3 illustrate a compiler creating objects with a minimum capacity of 15 characters but only filling five elements. The picture also illustrates that the elements in a string object use the same zero-indexing notation as arrays.

string Operators

In contrast to C-strings, the string class supports numerous operators that operate intuitively on the string's contents. Assigning a new meaning to an existing operator is called overloading and is described in chapter 10.

Operator Meaning Example
= Copies the contents of s3 to s1
Copies a C-string to string object s
s1 = s2;
s = "Hello, World!"
+ Concatenates s1 and s2; assignment stores the result in s s = s1 + s2;
+= Concatenation with assignment; left operand must be a variable s += s2
== Test for equality if (s1 == s2) . . .
!= Test for inequality if (s1 != s2) . . .
<, <=, >, >= Relational operators if (s1 < s2) . . .
[] and at() Character access char c = s1[i];
char c = s1.at(i);
<< and >> Input and output cout << s1;
cin >> s1;
string class operators. The string class overrides or reuses many basic C++ operators to make them work with string objects. For a program to use the string operators, at least one operand must be a string object. Furthermore:

 

#include <iostream>
#include <string>
using namespace std;

int main()
{
    string    s1 = "Hello";
    string    s2 = "World";
    string    s3 = s1;
    string    s4(s2);

    cout << s1 << "|" << s2 << endl;			// Hello|World
    cout << s3 << "|" << s4 << endl;			// Hello|World

    if (s1 == s2)					// s1 not equals s2
        cout << "s1 equals s2" << endl;
    else
        cout << "s1 not equals s2" << endl;

    if (s1 == s3)					// s1 equals s3
        cout << "s1 equals s3" << endl;
    else
        cout << "s1 not equals s3" << endl;

    s1 += ", ";
    s2 += "!";
    string    s5 = s1 + s2;
    cout << s5 << endl;					// Hello, World!

    for (size_t i = 0; i < s5.length(); i++)		// Hello, World!
        cout << s5[i];
    cout << endl;

    for (size_t i = 0; i < s5.length(); i++)		// Hello, World!
        cout << s5.at(i);
    cout << endl;

    string	s6 = "Apple";
    string	s7 = "Zebra";

    if (s6 < s7)
        cout << s6 << " precedes " << s7 << endl;	// Apple precedes Zebra
    if (s7 > s6)
    cout << s7 << " succeeds " << s6 << endl;		// Zebra succeeds Apple

    return 0;
}
string operator and function examples. The program output, shown as comments, demonstrates the behaviors of the operators and functions.