I spend three hours for this class today. It is a very interesting to consider the detail about how to make it more elegant. Now I will share with you guys, and expect for your comments.
SelfString.h
#ifndef SELF_STRING_H
#define SELF_STRING_H
#include <iostream>
using std::ostream;
using std::istream;
class String
{
public:
String(const char* str=NULL);
String(const String& other);
String& operator=(const String& other);
~String();
char& operator[](unsigned int index);
String& operator+=(const String& other);
String& operator+=(const char* str);
//bool operator==(const String& right) const;
//bool operator!=(const String& right) const;
int length() const;
const char* c_str() const;
bool empty() const;
void swap(String& other);
void append(const char* str);
void append(const String& other);
operator const char*() const;
/*
//Supply the friend method is not a good idea, it will break the encapsulation.
friend ostream& operator<<(ostream& ostr, const String& str);
friend istream& operator>>(istream& istr, String& str);
*/
private:
unsigned int _length;
char* _Data;
};
String operator+(const String& left, const String& right);
String operator+(const char* left, const String& right);
String operator+(const String& left, const char* right);
bool operator==(const String& left, const String& right);
bool operator!=(const String& left, const String& right);
ostream& operator<<(ostream& ostr, String& str);
istream& operator>>(istream& istr, String& str);
#endif
SelfString.cpp
#include "SelfString.h"
#include <string>
String::String(const char *str)
{
if(!str || (str[0] =='\0'))
{
//must use new[1], not new.
//Or else you need to do lot of useless works to identify the delete and delete[].
this->_Data = new char[1];
_Data[0]='\0';
_length = 0;
}
else
{
_length = strlen(str);
this->_Data = new char[_length + 1];
strcpy(_Data, str);
}
}
String::String(const String &other)
{
if(other._Data [0] == '\0')
{
_Data = NULL;
_length = 0;
}
else
{
_Data = new char[other._length+1];
_length = other._length;
strcpy(_Data, other._Data);
}
}
String::~String()
{
//Because of _Data are all applied by new[]
delete[] _Data;
_Data = NULL;
}
int String::length() const
{
return _length;
}
bool String::empty() const
{
if(_length == 0)
{
return true;
}
return false;
}
void String::swap(String& other)
{
if(other._Data[0] != '\0')
{
char* temp = new char[other._length + 1];
strcpy(temp, other._Data);
int len = other._length;
delete[] other._Data;
other._Data = new char[_length+1];
strcpy(other._Data, _Data);
delete[] _Data;
_Data = new char[other._length + 1];
_length = len;
strcpy(_Data, temp);
}
else
{
delete[] other._Data;
other._Data = new char[_length+1];
strcpy(other._Data, _Data);
delete[] _Data;
_Data = new char;
_length = 0;
_Data[0] = '\0';
}
}
void String::append(const char* str)
{
if(str && (str[0]!='\0'))
{
int len = strlen(str);
char* temp = new char[_length+1];
strcpy(temp, _Data);
delete[] _Data;
_Data = new char[_length + len + 1];
strcpy(_Data, temp);
strcpy(_Data+_length, str);
_length += len;
*(_Data + _length)='\0';
}
}
void String::append(const String& other)
{
if(other._Data[0]!= '\0')
{
int len = other._length;
char* temp = new char[_length+1];
strcpy(temp, _Data);
delete[] _Data;
_Data = new char[_length + len + 1];
strcpy(_Data, temp);
strcpy(_Data+_length, other._Data);
_length += len;
*(_Data + _length)='\0';
}
}
String& String::operator=(const String &other)
{
if(this == &other)
{
return *this;
}
delete[] _Data;
if(other._Data[0] == '\0')
{
this->_Data = NULL;
this->_length = 0;
}
else
{
_Data = new char[other._length + 1];
this->_length = other._length;
strcpy(_Data, other._Data);
}
return *this;
}
char& String::operator[](unsigned int index)
{
if(index>=0 && index<=this->_length-1)
{
return _Data[index];
}
//TODO:
}
String& String::operator+=(const String& other)
{
if(other._Data[0] != '\0')
{
this->append(other);
}
return *this;
}
String& String::operator+=(const char* str)
{
if(str)
{
this->append(str);
}
return *this;
}
/*
bool String::operator==(const String& right) const
{
if(this == &right)
{
return true;
}
if(this->_length != right._length)
{
return false;
}
return strcmp(this->_Data, right._Data)?false:true;
}
bool String::operator!=(const String& right) const
{
return !(this->operator ==(right));
}
*/
const char* String:: c_str() const
{
return this->_Data;
}
String::operator const char*() const
{
return this->_Data;
}
String operator+(const String& left, const String& right)
{
String newStr;
newStr.append(left);
newStr.append(right);
return newStr;
}
String operator+(const char* left, const String& right)
{
String newStr;
newStr.append(left);
newStr.append(right);
return newStr;
}
String operator+(const String& left, const char* right)
{
String newStr;
newStr.append(left);
newStr.append(right);
return newStr;
}
bool operator==(const String& left, const String& right)
{
if(&left == &right)
{
return true;
}
if(left.length() != right.length())
{
return false;
}
return strcmp(left.c_str(), right.c_str())?false:true;
}
bool operator!=(const String& left, const String& right)
{
return !(left == right);
}
ostream& operator<<(ostream& ostr, const String& str)
{
ostr<<str.c_str();
return ostr;
}
istream& operator>>(istream& istr, String& str)
{
std::string temp;
//Here has the some problem with std::cin, that is the input string can't have space.
istr >> temp;
str = temp.c_str();
return istr;
}
mainFile.cpp
#include <iostream>
#include <string>
#include "SelfString.h"
using std::cout;
using std::endl;
using std::cin;
int main()
{
//Unit Test for: Constructor, Assignment operator, Copy Constructor.
String str("I love C++.");
cout<<"1. Test for Constructor, should output: I love C++.: "<<str<<endl;
String str1;
str1 = "Do you like it?";
cout<<"2. Test for Construcor, should output: Do you like it?: "<<str1<<endl;
String str2(str);
cout<<"3. Test for copy Construcor,should output: I love C++.:"<<str2<<endl;
str1 = str2;
cout<<"4. Test for Assignment operator, should output: I love C++.:"<<str1<<endl;
//Unit Test for: istream& operator>>(istream& istr, String& str);
String str3;
cout<<"Please say something(no space) to the client, hit Enter to end: ";
cin>>str3;
cout<<"5. Test for operator>>, should same with what you input:"<<str3<<endl;
//Unit Test for: (1)void append(const char* str); (2)void append(const String& other);
String str4 = "1234";
String str5 = "1000";
str4.append("5678");
cout<<"6. Test for append(const char* str), should output: 12345678:"<<str4<<endl;
str4.append(str5);
cout<<"7. Test for append(const String& other), should output: 123456781000:"<<str4<<endl;
//Unit Test for: operator const char*();
String myName("FuQiang");
int cmp_should_less_than_zero = strcmp(myName, "Walle");
cout<<"Implicit to convert the String to const char*,";
cout<<"so strcmp() can accept the String as parameter.";
cout<<"Should return value less than zero:"<< cmp_should_less_than_zero<<endl;
int cmp_should_EQ_with_zero = strcmp(myName, "FuQiang");
cout<<"Should return value EQ with zero:" << cmp_should_EQ_with_zero<<endl;
//Unit Test for: operator+
String one = "One";
String two = "Two";
String Str5 = one + two;
cout<<"8. Test for operator+, should output: OneTwo:"<<Str5<<endl;
String Str6 = "Three" + one;
cout<<"9. Test for operator+, should output:ThreeOne:"<<Str6<<endl;
String Str7 = two + "Four";
cout<<"10. Test for operator+, should output TwoFour:"<<Str7<<endl;
//Unit Test for: void swap(String& other);
String swapLeft("Left");
String swapRight("Right");
swapLeft.swap(swapRight);
cout<<"11. Test for swap(String& other), should output: Right left:"<<swapLeft<<" "<<swapRight<<endl;
//Unit Test for: operator+=
String plusEqualOne("one");
String sum;
sum += plusEqualOne;
cout<<"12. Test for operator+=, should output: one:"<<sum<<endl;
sum += "Two";
cout<<"13. Test for operator+=, should output: oneTwo:"<<sum<<endl;
//Unit Test for: operator== and operator!=
String equal1 = "fuqiang";
String equal2 = "fuqiang";
cout<<"14. Test for operator==, should output 1:"<<(equal1 == equal2) <<endl;
String equal3 = "Fuqiang";
cout<<"15. Test for operator==, should output 0:"<<(equal1 == equal3) <<endl;
cout<<"16. Test for operator!=, should output 1:"<<(equal1 != equal3) <<endl;
cout<<"17. Test for operator!=, should output 0:"<<(equal1 != equal2) <<endl;
system("PAUSE");
}
Some items I need to spend some time to consider:
1. How to elegantly
catch and handle the exception of applying resources on heap (new operator).