#include <iostream>
#include <iomanip>
#include <cstring> // strcpy and strcat prototypes
#include <cstdlib> // exit prototype
using namespace std;
class String
{
friend ostream &operator<<(ostream &, const String &);
friend istream &operator>>(istream &, String &);
public:
String(const char * = ""); // conversion/default constructor
String(const String &); // copy constructor
~String(); // destructor
const String &operator=(const String &); // assignment operator
const String &operator+=(const String &); // concatenation operator
bool operator!() const; // is String empty?
bool operator==(const String &) const; // test s1 == s2
bool operator<(const String &) const; // test s1 < s2
bool operator!=(const String &right) const; // test s1 != s2
bool operator>(const String &right) const; // test s1 > s2
bool operator<=(const String &right) const;// test s1 <= s2
bool operator>=(const String &right) const; // test s1 >= s2
char &operator[](int); // subscript operator (modifiable lvalue)
int getLength() const; // return string length
private:
int length; // string length (not counting null terminator)
char *sPtr; // pointer to start of pointer-based string
void setString(const char *); // utility function
}; // end class String
ostream &operator<<(ostream &os, const String & str)
{
if(str.sPtr) os << str.sPtr;
return os;
}
istream &operator>>(istream & is, String & str)
{
char temp[200]; temp[0] = 0; is >> temp;
str.setString(temp);
return is;
}
String::String(const char * s)
{
sPtr = NULL;
this->setString(s);
if (s) cout << "Conversion (and default) constructor: "<< s << endl;
}
String::String(const String& a)
{
sPtr = NULL;
if (a.length) this->setString(a.sPtr);
if (a.length) cout << "Copy constructor: " << a.sPtr << endl;
}
String::~String()
{
if (sPtr){
cout << "Destructor: " << sPtr << endl;
delete[] sPtr;
}
sPtr = NULL;
}
char & String::operator[](int i)
{
if (i < length)
return sPtr[i];
return sPtr[length];
}
int String::getLength() const
{
return length;
}
void String::setString(const char * s)
{
length = 0;
if (sPtr) delete[] sPtr;
sPtr = NULL;
if (s && s[0]){
delete[] sPtr;
length = strlen(s);
sPtr = new char[length + 1];
strcpy(sPtr, s);
}
}
bool String::operator!() const
{
return length == 0;
}
bool String::operator<(const String &right) const
{
return strcmp(sPtr, right.sPtr) < 0;
}
bool String::operator>(const String &right) const
{
return strcmp(sPtr, right.sPtr) > 0;
}
bool String::operator>=(const String &right) const
{
return strcmp(sPtr, right.sPtr) >= 0;
}
bool String::operator<=(const String &right) const
{
return strcmp(sPtr, right.sPtr) <= 0;
}
bool String::operator!=(const String &right) const
{
return strcmp(sPtr, right.sPtr) != 0;
}
bool String::operator==(const String &right) const
{
return strcmp(sPtr, right.sPtr) == 0;
}
const String & String::operator+=(const String & s)
{
char* tmp = new char[s.length + length + 1];
strcpy(tmp, sPtr);
strcpy(tmp + length, s.sPtr);
if (sPtr) delete[]sPtr;
sPtr = tmp;
length = s.length + length;
return *this;
}
const String & String::operator=(const String & s)
{
cout << "operator= called" << endl;
this->setString(s.sPtr);
return *this;
}
int main()
{
String s1("happy");
String s2(" birthday");
String s3;
// test overloaded equality and relational operators
cout << "s1 is \"" << s1 << "\"; s2 is \"" << s2
<< "\"; s3 is \"" << s3 << '\"'
<< boolalpha << "\n\nThe results of comparing s2 and s1:"
<< "\ns2 == s1 yields " << (s2 == s1)
<< "\ns2 != s1 yields " << (s2 != s1)
<< "\ns2 > s1 yields " << (s2 > s1)
<< "\ns2 < s1 yields " << (s2 < s1)
<< "\ns2 >= s1 yields " << (s2 >= s1)
<< "\ns2 <= s1 yields " << (s2 <= s1);
// test overloaded String empty (!) operator
cout << "\n\nTesting !s3:" << endl;
if (!s3)
{
cout << "s3 is empty; assigning s1 to s3;" << endl;
s3 = s1; // test overloaded assignment
cout << "s3 is \"" << s3 << "\"";
} // end if
// test overloaded String concatenation operator
cout << "\n\ns1 += s2 yields s1 = ";
s1 += s2; // test overloaded concatenation
cout << s1;
// test conversion constructor
cout << "\n\ns1 += \" to you\" yields" << endl;
s1 += " to you"; // test conversion constructor
cout << "s1 = " << s1 << "\n";
// test copy constructor
String *s4Ptr = new String(s1);
cout << "\n*s4Ptr = " << *s4Ptr << "\n";
// test destructor
delete s4Ptr;
// test using subscript operator to create a modifiable lvalue
s1[0] = 'H';
s1[6] = 'B';
cout << "\ns1 after s1[0] = 'H' and s1[6] = 'B' is: "
<< s1 << "\n";
// test subscript out of range
cout << "Attempt to assign 'd' to s1[30] yields:" << endl;
s1[30] = 'd'; // ERROR: subscript out of range
return 0;
} // end main