1// String.h
2// Author: t a y l o r@msoe.edu and section 6 of the
3// MSOE Spring 2001 CS183 course
4// Date: 4-10-2001
5// Purpose: Defines a String class which demostrates a simplified
6// version of the C++ standard string class.
7// Modified: t a y l o r@msoe.edu, 4-8-02 => const operator[] now returns const ref
8// => now use szType typedef for object size
9
10#ifndef STRING_H
11#define STRING_H
12
13#include <iostream>
14using std::istream;
15using std::ostream;
16
17class String {
18public:
19 // Define szType to be the type of the object containing the size of the
20 // String
21 typedef unsigned int szType;
22
23 // Default constructor
24 String();
25
26 // Copy constructor
27 String(const String& rhs);
28
29 // One argument constructor that takes a character array as the initial
30 // value for the string
31 String(char str[]);
32
33 // Destructor
34 ~String();
35
36 // Assignment operator
37 String& operator=(const String& rhs);
38
39 // Accessor returning the number of elements in the String
40 szType size() const;
41
42 // Concatenate operator: adds the String passed, str, to the
43 // current String
44 // e.g., String name("Jon"); String last("Dough");
45 // name += last; // "JonDough"
46 String& operator+=(String rhs);
47
48 // Accessor that returns the (i+1)st element of the String
49 const char& operator[](szType i) const;
50
51 // Mutator that returns a reference to the (i+1)st element of the String
52 // This version of the operator may be used as an lvalue
53 char& operator[](szType i);
54
55 // Inserts a String into the input stream, os
56 void insertion(ostream& os) const;
57
58private:
59 szType numEl;
60 char* letters;
61};
62
63// Auxilliary insertion operator which allows String objects to be
64// inserted into an output stream
65ostream& operator<<(ostream& os, const String& str);
66#endif
1// String.cpp
2// Author: t a y l o r@msoe.edu and section 6 of the
3// MSOE Spring 2001 CS183 course
4// Date: 4-10-2001
5// Purpose: Defines a String class which demostrates a simplified
6// version of the C++ standard string class.
7// Modified: t a y l o r@msoe.edu, 4-8-02 => const operator[] now returns const ref
8// => now use szType typedef for object size
9
10#include "String.h"
11#include <cassert>
12
13// t a y l o r@msoe.edu, 4-10-01
14String::String() : numEl(0), letters(0)
15{
16 // Nothing else to do
17}
18
19// t a y l o r@msoe.edu, 4-10-01
20// Modified: t a y l o r@msoe.edu, 4-8-02 => now uses szType typedef
21String::String(const String& rhs) : numEl(rhs.numEl), letters(0)
22{
23 if(rhs.numEl) { // rhs is not an empty String
24 letters = new char[numEl];
25 }
26 for(szType i=0; i<numEl; ++i) {
27 letters[i] = rhs.letters[i];
28 }
29}
30
31// t a y l o r@msoe.edu, 4-10-01
32// Modified: t a y l o r@msoe.edu, 4-8-02 => now uses szType typedef
33String::String(char str[]) : numEl(0), letters(0)
34{
35 while(str[numEl]!='\0') {
36 ++numEl;
37 }
38 if(numEl) { // not an empty String
39 letters = new char[numEl];
40 }
41 for(szType i=0; i<numEl; ++i) {
42 letters[i] = str[i];
43 }
44}
45
46// t a y l o r@msoe.edu, 4-10-01
47String::~String()
48{
49 if(numEl) {
50 delete [] letters;
51 }
52}
53
54// t a y l o r@msoe.edu, 4-10-01
55String& String::operator=(const String& rhs)
56{
57 // Check for self-assignment
58 if(this!=&rhs) {
The if statement above makes sure that we don't
assign an object to itself. this is a pointer to the
calling object, i.e., it is the address in memory where the calling object
resides. rhs is the object whose value we want to copy
and &rhs the address in memory where it is stored.
If this and &rhs are the same, then
they are both stored in the same place in memory and must be
the same object. In this case, not checking for self-assignment is
inefficient. Suppose that A is a String
object and we do the following: A = A;. This function is
called with the calling object being A and the
object passed in, rhs, also being A.
Therefore, numEl and rhs.numEl are
the same and letters and rhs.letters
both point to the same character array. Without the self assignment
check, we would be forced to copy all of the letters into the same location,
clearly inefficient.
It is important to check for self assignment whenever implementing
the assignment operator for a class that has dynamically allocated memory.
In this case are implementation would be less efficient; however, there
are situations where it can be down right disastrous. For example, we could
remove the if statement immediately following this comment
and still have a valid implementation of the assignment operator (it's
just a little less efficient when assigning two Strings
of the same length equal to each other); however, now if we were to remove
the self assignment check as well, we would have major problems. Can you
see why?
Removing the two if statements would result in us
deallocating the memory used to store the calling object. We would then
allocate new memory to store the character array from rhs,
but when we tried to copy the characters from rhs we
would discover that they are no longer there (we just deleted them).
|
59 if(numEl!=rhs.numEl) {
60 numEl = rhs.numEl;
61 delete [] letters;
62 if(rhs.numEl) {
63 letters = new char[numEl];
64 }
65 }
66 for(szType i=0; i<numEl; ++i) {
67 letters[i] = rhs.letters[i];
68 }
69 }
70 return *this;
71}
72
73// t a y l o r@msoe.edu, 4-10-01
74// Modified: t a y l o r@msoe.edu, 4-8-02 => now uses szType typedef
75String::szType String::size() const
76{
77 return numEl;
78}
79
80// t a y l o r@msoe.edu, 4-10-01
81// Modified: t a y l o r@msoe.edu, 4-8-02 => now uses szType typedef
82String& String::operator+=(String rhs)
83{
84 if(numEl+rhs.numEl) {
85 char* ptr = new char[numEl+rhs.numEl];
86 szType i=0;
87 for(; i<numEl; ++i) {
88 ptr[i] = letters[i];
89 }
90 for(i=0; i<rhs.numEl; ++i) {
91 ptr[numEl+i] = rhs.letters[i];
92 }
93 delete [] letters;
94 letters = ptr;
95 numEl += rhs.numEl;
96 }
97 return *this;
98}
99
100// t a y l o r@msoe.edu, 4-10-01
101// Modified: t a y l o r@msoe.edu, 4-8-02 => now returns const ref
102// => now uses szType typedef
103const char& String::operator[](String::szType i) const
104{
105 assert(i<numEl); // MSVC++ does not do this check
106 return letters[i];
107}
108
109// t a y l o r@msoe.edu, 4-10-01
110// Modified: t a y l o r@msoe.edu, 4-8-02 => now uses szType typedef
111char& String::operator[](String::szType i)
112{
113 assert(i<numEl); // MSVC++ does not do this check
114 return letters[i];
115}
116
117// t a y l o r@msoe.edu, 4-10-01
118// Modified: t a y l o r@msoe.edu, 4-8-02 => now uses szType typedef
119void String::insertion(ostream& os) const
120{
121 for(szType i=0; i<numEl; ++i) {
122 os << letters[i];
123 }
124}
125
126// t a y l o r@msoe.edu, 4-10-01
127ostream& operator<<(ostream& os, const String& str)
128{
129 str.insertion(os);
130 return os;
131}