In this article, we will create our custom string class which will have the same functionality as the existing string class.
I won’t be implementing all of the functionalities of the string class instead I would implement the necessary functionalities that are much more used.
So, get your IDE or whatever setup you have and let’s get started.
First and foremost we need our class body. I am gonna call my class Thread (as it kind of gives the same feeling as strings ). It’s gonna have a char pointer
to hold our data . As we proceed our class will evolve but it currently looks like this :-
using namespace std;class Thread
Notice that I have included the cstring library as it gives access to strlen function to get length of char array which we are gonna use a few times. Our class currently has a normal constructor, a destructor and a char pointer.
Now we need some functions to support different ways of creating Thread objects. Below are a normal constructor, a parameterized constructor, a copy constructor and the destructor. I will be writing every method outside the class while only declaring them in the class using the scope resolution operator ( :: ).
str = nullptr;
}Thread::Thread(const char* buffer)
this->setThread(buffer);}Thread::Thread(const Thread& source)
char* buffer = source.getThread();
I hope that you know how to use the this keyword or you can check it here. I have also added two methods namely the setThread and getThread methods which we are going to implement next. The destructor is quite necessary here as it deallocates the memory that our char pointer consumes when a Thread object is created. Deallocating is very important or it would result in a lot of pointer problems which we don’t want.
void setThread(const char*);
char* getThread() const;
void Thread::setThread(const char* buffer)
int n = strlen(buffer); //Allocating str memory of char[n+1]
// +1 for the null character
str = new char[n+1]; for(;i<n;i++)
str[i] = buffer[i]; //Copying from buffer to str
str[i] = '\0';
} char* Thread::getThread() const
return str; //Returning the char pointer
The codes in the above methods are simple and I don’t think explanations are necessary. The reason for declaring these methods as private is we don’t want to have another method for initializing our object except for our constructors.
Cool. Our class now supports for creating and initializing objects. Even though these constructors are good enough for initializing our object there is one more method for initializing using the assignment ( = ) operator and this method is most widely used. We implement this by overloading the assignment operator.
void operator = (const char*);//Definition
void Thread::operator = (const char* buffer)
I think this is sufficient for initializing the object. Let’s add a method to return the length of the string or our Thread object.
Let’s implement string concatenation method by overloading the plus operator. We will implement method to concatenate two Thread objects.
friend Thread operator + (const Thread&,const Thread&);
char* add(const char*,const char*) const;//Definitionchar* Thread::add(const char* x,const char* y) const
int n = strlen(x) + strlen(y);
char* temp = new char[n+1];
temp[k++] = x[i++];
temp[k++] = y[j++];
temp[k] = '\0';
}Thread operator + (const Thread& lhs,const Thread& rhs)
char* x = lhs.getThread();
char* y = rhs.getThread();
char* res = lhs.add(x,y);
Here I have overloaded the plus operator and implemented a private add method which is a helper method for the plus operator. Let’s analyze the add method and then the plus operator.
The add method takes two char pointer as parameters x and y. It creates a new dynamic char array whose length is sum of lengths of x and y + 1. The +1 is for null character. It then loops and first copies values of x and then values of y and then returns the dynamically created array pointer.
The overloaded operator is declared as friend function as it’s easy to work with operator overloading when declared as friend function. It takes two Thread objects and calls the add method upon one of the objects passing the char pointer of the two Thread objects. The pointer returned by add method is stored in “res” and then a new Thread object is created passing “res” in it. Deleting the “res” is very important as it has been allocated some memory in the add method and deallocating it is very important.
Let’s try an example for all the work we have done until now.
//Creating an object
z = s + t;
The only thing that is left is a way to display our object. We can do this by overloading the insertion ( << ) operator.
friend std::ostream& operator << (std::ostream&,Thread&);//Definition
ostream& operator << (ostream& cout,Thread& rhs)
char* res = rhs.getThread();
The insertion operator takes two parameter. The first one is ostream object reference which is the cout that we usually use for displaying output and the second parameter is the Thread object reference. The return type is ostream object reference so that it can be used again in the same line.
Overloading the insertion operator makes it easy to display our object as shown below.
Now we have implemented our own string class which is dynamic and cool. Source code for this article — here.
P.S. :- This is not a thorough implementation of the string class. There are still many improvements that can be made. For example overloading the plus operator for concatenating Thread object and char array or Thread object and a char. We don’t have any method for getting character at some index. Implementing that would be nice as well.