Yesterday, my senior brother asked another test question, allowing us to implement a MyString class that is similar to the string class. It was a headache at first, but when I was really writing the code myself, I was excited to find that this process is really a valuable opportunity, giving me the opportunity to familiarize myself with and review a lot of C++ knowledge—class design, constructing destructors, member functions, friend functions, quotations, overloading, string operations, and dynamic memory distribution. . . . . So I spent half a day writing more than 300 lines of code yesterday and carefully conducted relevant tests, modifications and summary. Because the content is a bit rich, I want to write it out in several times and make it clearer in structure.
Class space allocation: The class allocates independent space to each object of its data to store its data members, and all objects are publicly accessible to the class methods. At the same time, in the independent space of the object, the space dynamically allocated by data members is not included. The object only records the address of the dynamically allocated space (so when the destructor call is called, the object space is only deleted, and the address dynamically allocated needs to be deleted with new).
1. Class declaration—:
1. Constructor:
Specifically used to build new objects, allocate necessary memory space to member data and assign values to member data of new objects.
Default constructor:
When explicit initialization values are not provided, the constructor used to create the object (so it generally has no parameters)
MyString();
Copy the constructor:
Used to copy an object into the newly created object (of course, this copied object must already exist).
MyString(const MyString &str);
Given a constructor with certain initialization parameters:
The values in the parameter list are assigned to each member function of the newly created object at once:
MyString(const char*str);
2. Destructor:
When the object expires, the memory space occupied by the object is deleted, and when the memory requested by New is empty when the object is created, delete is also called in the destructor to free the originally allocated memory space to prevent memory leakage.
~MyString();
3. Member functions:
Overload assignment member functions:
MyString &operator=(const MyString &str); //Use existing string object to assign values to an object through =MyString &operator=(const char*str); // Directly use constant strings to assign values
General assignment functions:
MyString &assign(const MyString&str); MyString &assign(const char*sstr);
Several member functions that handle strings:
size_t getsize()const; //Return the string sizevoid clear(); //Clear the stringbool empty(); //Judge whether the string is emptyvoid swap(MyString &str); //Swap two stringsint compare(const MyString &str)const; //Compare the size of 2 strings//The first const says that the string in the explicit call cannot be changed, and the const outside the brackets indicates that the string in the implicit call cannot be changed, and read only dataint compare(const char*str);
Append functions:
MyString &operator+=(const MyString&str); MyString &operator+=(const char*str); MyString &append(const MyString&str); MyString &append(const char *str);
Generate string:
MyString substr(size_t pos = 0,n=npos) const;Generate a string, starting from the 0th position, the length is n. If N exceeds the length, it is the length of the output string.
4. Friendly function (operator overload):
Friendly functions are generally defined in class declarations. They do not belong to class member functions, but they can access all data members of the class just like class member functions.
friend bool operator==(const MyString &str1,const MyString &str2); friend bool operator==(const char *str,const MyString &str2); friend bool operator==(const MyString &str1,const MyString *str2); friend bool operator>(const MyString &str1,const MyString &str2); friend bool operator>(const char*str1,const MyString &str2); friend bool operator>(const MyString &str1,const char*str2);
There are also various comparisons.
friend MyString operator+(const MyString &str1,const MyString &str2); friend MyString operator+(const char*str1,const MyString &str2); //Add two strings togetherfriend MyString operator+(const MyString &str1,const char*str2); friend ostream & operator<<(ostream &os,const MyString &str); //Overload of output command characters
5. Member data variables:
char *string; // Pointer to stringint length; //Length of stringstatic const int string_number = 0; //Count the number of created strings
2. Implement the .cpp file:
1. Constructor and destructor:
MyString::MyString() { length = 0; string = new char; char *s = "/0"; memcpy(string,s,1); ++string_number; } MyString::MyString(const char*str) { length = strlen(str); string = new char(length+1); memcpy(string,s,length); ++string_number; } MyString::MyString(MyString &str) { length = ; string = ; ++string_number; } MyString::~MyString() { delete[]string; --string_number; }
Several issues to note:
1) All data members must be initialized in the constructor.
2) Pay attention to the correspondence between left and right types when assigning values to pointers to strings.
char *s represents a pointer to a string, and all the right side must be a string constant "/0", not '/0'.
3) A pointer can only point to one address, not two at the same time.
After assigning an address to string, the next step is to determine the specific content stored in the assigned address. At this time, we all use strcpy() or
memcpy() stores the corresponding string in the address.
If we did this:
MyString::MyString() { length = 0; string = new char; string = "/0"; ++string_number; }
Then we will not find any mistakes when compiling and implementing it, but the destructor uses delete【】 to free memory and make the execution result garbled, because string="/0"
Let it point to a string and no memory space is allocated, so an error will occur when it is released.
4) Important statements in the destructor delete【】Don't forget
When used, the destructor will only free the space allocated for the object, but the space of the object only stores the address of the data member allocated memory, so the data member is not freed.
The memory space must be released using delete[] to prevent memory leakage.
2. Overload operator member functions:
MyString &MyString::operator+=(const MyString&str) { char *dest; dest = new char[+length+1]; memcpy(dest,string,length); memcpy(dest+length,,+1); delete[]string; length = length+; string = dest; return*this; } MyString &MyString::operator+=(const char*str) { char *dest; dest = new char[strlen(str)+length+1]; memcpy(dest,string,length); memcpy(dest+length,str,strlen(str)+1); delete[]string; string = dest; return *this; } //Standard assignmentMyString &MyString::operator=(const MyString&str) { if(&str == this) return *this; delete[]string; string = new char[]; memcpy(string,,); length = ; return *this; }
Several issues to note:
1) In the += operation, the final string length of the object calling the function is definitely greater than its original length, so during this function call process, we must reassign a piece of the string.
Two memory areas of string length and size. However, because the return value of the function must be a reference to the original calling object, we need to define an intermediate variable pointer to store 2
The string merge result is, and finally release the original memory area of the string pointer, and then let it point to the merge string.
2) The "=" assignment operation is definitely different from the initialization of the constructor.
Before using this method, the object must have at least had a certain value by calling the constructor data member. So at this time we first determine whether the two objects are
equal. If equal, return to the original object, if not:
Then the string lengths of the two objects must be different. So we first free up the original string memory space, and then allocate the memory space according to the string length of the assignment object and add the characters
Copy the string memory.
3. Several functions for string processing:
size_t MyString::getsize(MyString &str) { return strlen(); } void MyString::clear() { length = 0; while(string!='/0') *string ='/0'; } bool MyString::empty() { return strlen(string)==0; } int MyString ::compare(const MyString &str) { return compare(string,); } void MyString::swap(MyString &str) { char *temp; temp = string; string = ; str = temp; } Mystring MyString::substr(sizez_t pos=0,size_t n )const { MyString string; delete[]; if(n>length) { = length; = new char[length+1]; memcpy(,string,length+1); return string; } length = n; = new char[length+1]; memcpy(,string,length+1); return string; }
Several issues to note:
1) In the implementation of these functions, we can directly call several <> functions for string processing in C language to implement them.
2) Note in the clear() function that just setting the character in each memory area to 0 cannot free up memory space through delete[], which is easy to cause it together with the destructor.
Releasing memory space twice causes an error.
3) In this function of swap() to implement swap, we can directly define the intermediate variable pointer implementation without reallocating the memory space for all transfer. This is for the destructor
The destruction has no effect.
4. Friendly function:
friend bool operator==(const MyString &str1,const MyString &str2) return strcmp(,)==0; friend MyString operator+(const MyString &str1,const MyString &str2) { MyString mystring; char *dest; dest = new char[++1]; memcpy(dest,,); memcpy(dest+,,+1); delete[]; = dest; = +; return mystring; } friend ostream &operator<<(ostream &os,const MyString &str) { os<<; return os; }
The issues you pay attention to are similar to those above, so I won't repeat them here~~~
The implementations of the other functions are basically the same ~