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.
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. |
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.
#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)
(b) - s2 and s3
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.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; |
at() is a function and not an operator. If s is an instance of the string class, then both s.at(i) and [i] reference the i-th character in string s, but the at function verifies that 0 ≤ i < s.length() while the index operator, [], does not.>>, works for very simple strings, it does not work for strings that contain spaces or tab characters. The next section presents a more reliable way of entering strings.
#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;
}