Question
This assignment introduces the concept of dynamic memory allocation, destructors, copy constructors, and overloading the assignment operator, , and also provides some insight into how
This assignment introduces the concept of dynamic memory allocation, destructors, copy constructors, and overloading the assignment operator, , and also provides some insight into how the C++ string class works.
Assignment
In this assignment, you will create a class to represent a string of characters. You can think of this class as a simplified version of the C++ string class.
Program
You will need to write one class for this assignment. A main program to test your class has been provided.
The NIUString class
The NIUString class represents a string of characters. You can think of it as a "wrapper" we can put around an array of char that provides additional functionality (like the ability to assign one string to another, compare strings using the relational operators, etc.). Like the other classes we've written this semester, this class should be implemented as two separate files.
The class declaration should be placed in a header file called NIUString.h. Include header guards to prevent it from accidentally being #included more than once in the same source code file.
Data Members
The NIUString class should contain the following private data members:
a pointer to a char. I'll refer to this data member as the string array pointer. It will be used to dynamically allocate an array of char (the string array).
an unsigned integer or size_t variable used to keep track of the number of elements in the string array. I'll refer to this data member as the string capacity.
an unsigned integer or size_t variable used to store the current length of the C string stored in the string array. I'll refer to this data member as the string size. The string size must always be less than or equal to the string capacity.
In addition to the changes to the data members described above, your class declaration will need prototypes for methods described below.
Methods
The implementations of the class methods should be placed in a separate source code file called NIUString.cpp. Make sure to #include "NIUString.h" at the top of this file.
The NIUString class should have the following methods (most of which are quite small):
NIUString::NIUString()
This "default" constructor for the NIUString class should initialize a new NIUString object to an empty string with a capacity of 0. The required logic is:
< >Set the string size for the new object to 0.
Set the string capacity for the new object to 0.
Set the string array pointer for the new object to the special value nullptr.
NIUString::NIUString(const char* other)
This constructor for the NIUString class should initialize a new NIUString object to the C string other. The required logic is:
< >Set the string size for the new object to the length of the C string other.
Set the string capacity for the new object to the string size.
If the string capacity is 0, set the string array pointer for the new object to nullptr. Otherwise, use the string array pointer for the new object to allocate an array of char. The number of elements in the new string array should be equal to the string capacity.
Copy the characters of the C string other (up to, but not including the null character) into the string array.
NIUString::NIUString(const NIUString& other)
This "copy constructor" for the NIUString class should initialize a new NIUString object to the same string as the existing NIUString object other. The required logic is:
< >Set the string size for the new object to the string size of other.
Set the string capacity for the new object to the string capacity of other.
If the string capacity is 0, set the string array pointer for the new object to nullptr. Otherwise, use the string array pointer for the new object to allocate an array of char. The number of elements in the new string array should be equal to the string capacity.
Copy the contents of the string array of other into the string array of the new object. If other has a string size of 0, this loop will exit immediately.
NIUString::~NIUString()
The destructor for the NIUString class can simply call the clear() method described below.
NIUString& NIUString::operator=(const NIUString& other)
This overloaded assignment operator should assign one NIUString object (the object other) to another (the object that called the method, which is pointed to by this). The required logic is:
< >Check for self-assignment. If the address stored in the pointer this is the same as the address of the object other, then skip to the final step.
Delete the string array for the object pointed to by this.
Set the string size for the object pointed to by this to the string size of other.
Set the string capacity for the object pointed to by this to the string capacity of other.
If the string capacity is 0, set the string array pointer for the object pointed to by this to nullptr. Otherwise, use the string array pointer to allocate an array of char. The number of elements in the new string array should be equal to the string capacity.
Copy the contents of the string array of other into the string array of the object pointed to by this.
Return *this.
NIUString& NIUString::operator=(const char* other)
This overloaded assignment operator should assign a C string (the string other) to an NIUString object (the object that called the method, which is pointed to by this). The required logic is:
< >Delete the string array.
Set the string size for the object pointed to by this to the length of the C string other.
Set the string capacity for the object pointed to by this to the string size.
If the string capacity is 0, set the string array pointer for the object pointed to by this to nullptr. Otherwise, use the string array pointer to allocate an array of char. The number of elements in the new string array should be equal to the string capacity.
Copy the contents of the C string other (up to, but not including the null character) into the string array of the object pointed to by this.
Return *this.
size_t NIUString::capacity() const
This method should return the string capacity.
size_t NIUString::size() const
This method should return the string size.
bool NIUString::empty() const
This method should return true if the string size is 0. Otherwise, it should return false.
void NIUString::clear()
This method should set the string size and string capacity to 0. It should should then use the delete[] operator to delete the string array. Finally, the string array pointer should be set to nullptr.
void NIUString::reserve(size_t n)
This method modifies an object's string capacity without changing its size or the contents of the string array. The required logic is:
< >If n is less than the string size or n is equal to the current string capacity, simply return.
Set the string capacity to n.
Declare a temporary array pointer (a pointer to a char).
If the string capacity is 0, set the temporary array pointer to nullptr. Otherwise, use the temporary array pointer to allocate an array of char. The number of elements in the new temporary array should be equal to the string capacity.
Copy the contents of the string array into the temporary array.
Delete the string array.
Set the string array pointer to the temporary array pointer.
bool NIUString::operator==(const NIUString& rhs) const
This method should return true if the characters stored in the string array of the object that called the method are identical to the characters stored in the string array of the NIUString object passed in as rhs.
The logic for this method is less difficult that it might initially appear to be. The first step is to compare the string sizes of the two strings. If they are different, return false (two strings of different lengths can not be equal).
Otherwise, loop through the elements of both string arrays, starting at 0 and stopping when you reach the string size. (The size of which string doesn't matter, since you know they're the same by this point.) Compare the current element from each string array. If characters are different, return false. If the characters are the same, don't return true; do nothing and let the loop continue.
Once the loop ends and you've reached the end of both strings, return true.
bool NIUString::operator==(const char* rhs) const
This method should return true if the characters stored in the string array of the object that called the method are identical to the characters of the C string passed in as rhs (up to, but not including the null character).
The logic for this method is similar to that of the previous method.
const char& NIUString::operator[](size_t pos) const
This method should return element pos of the string array.
char& NIUString::operator[](size_t pos)
This method should return element pos of the string array.
In addition to the methods described above, you will need to write a couple of standalone functions. These functions are not (and can not be) methods. You should
Include a friend declaration for each of these functions in the NIUString class definition.
Put the definitions for these functions in NIUString.cpp.
ostream& operator<<(ostream& lhs, const NIUString& rhs)
This method should loop through the characters of the string array of the NIUString object passed in as rhs and print them one at a time using the stream object passed in as lhs.
bool operator==(const char* lhs, const NIUString& rhs)
This method should return true if the characters of the C string passed in as lhs (up to, but not including the null character) are identical to the characters stored in the string array of the NIUString object passed in as rhs.
The logic for this function is similar to that of the two relational operator methods.
Driver Program
A short main program to test your class is given below. Either type in this program or copy it to your UNIX account from the pathname ~t90kjm1/CS241/Code/Spring2017/Assign5/assign5.cpp.
/********************************************************************* PROGRAM: CSCI 241 Assignment 5 PROGRAMMER: your name LOGON ID: your z-ID DUE DATE: due date of assignment FUNCTION: This program tests the functionality of the NIUString class. *********************************************************************/ #include#include "NIUString.h" using std::cout; using std::endl; int main() { cout << "Testing default constructor "; const NIUString s1; cout << "s1: " << s1 << endl; cout << "s1 size: " << s1.size() << endl; cout << "s1 capacity: " << s1.capacity() << endl; cout << "s1 is " << ((s1.empty()) ? "empty " : "not empty "); cout << endl; cout << "Testing second constructor "; NIUString s2 = "some text"; cout << "s2: " << s2 << endl; cout << "s2 size: " << s2.size() << endl; cout << "s2 capacity: " << s2.capacity() << endl; cout << "s2 is " << ((s2.empty()) ? "empty " : "not empty "); cout << endl; cout << "Testing second constructor with long string "; NIUString s3 = "This is a really long string, but all of it will still end up in the array - pretty neat, huh?"; cout << "s3: " << s3 << endl; cout << "s3 size: " << s3.size() << endl; cout << "s3 capacity: " << s3.capacity() << endl; cout << endl; cout << "Testing write form of subscript operator "; s2[0] = 'S'; s2[5] = 'T'; cout << "s2: " << s2 << endl << endl; cout << "Testing read form of subscript operator "; cout << "s2: "; for (size_t i = 0; i < s2.size(); i++) cout << s2[i]; cout << endl << endl; cout << "Testing reserve() method "; s2.reserve(9); cout << "s2: " << s2 << endl; cout << "s2 size: " << s2.size() << endl; cout << "s2 capacity: " << s2.capacity() << endl; cout << "s2 is " << ((s2.empty()) ? "empty " : "not empty "); cout << endl; s2.reserve(30); cout << "s2: " << s2 << endl; cout << "s2 size: " << s2.size() << endl; cout << "s2 capacity: " << s2.capacity() << endl; cout << "s2 is " << ((s2.empty()) ? "empty " : "not empty "); cout << endl; s2.reserve(15); cout << "s2: " << s2 << endl; cout << "s2 size: " << s2.size() << endl; cout << "s2 capacity: " << s2.capacity() << endl; cout << "s2 is " << ((s2.empty()) ? "empty " : "not empty "); cout << endl; s3.reserve(10); cout << "s3: " << s3 << endl; cout << "s3 size: " << s3.size() << endl; cout << "s3 capacity: " << s3.capacity() << endl; cout << "s3 is " << ((s3.empty()) ? "empty " : "not empty "); cout << endl; cout << "Testing equality operators "; const NIUString s4 = "Some Text"; cout << "s2 and s4 are " << ((s2 == s4) ? "equal " : "not equal "); cout << "s3 and s4 are " << ((s3 == s4) ? "equal " : "not equal "); cout << "s4 and \"Some Text\" are " << ((s4 == "Some Text") ? "equal " : "not equal "); cout << "s4 and \"More Text\" are " << ((s4 == "More Text") ? "equal " : "not equal "); cout << "\"Some Text\" and s4 are " << (("Some Text" == s4) ? "equal " : "not equal "); cout << "\"More Text\" and s4 are " << (("More Text" == s4) ? "equal " : "not equal "); cout << "Testing clear() method "; s3.clear(); cout << "s3: " << s3 << endl; cout << "s3 size: " << s3.size() << endl; cout << "s3 capacity: " << s3.capacity() << endl; cout << "s3 is " << ((s3.empty()) ? "empty " : "not empty "); cout << endl; cout << "Testing copy constructor "; NIUString s5(s4); cout << "s5: " << s5 << endl; cout << "s5 size: " << s5.size() << endl; cout << "s5 capacity: " << s5.capacity() << endl; cout << endl; cout << "Testing assignment operator "; s3 = s5; cout << "s3: " << s3 << endl; cout << "s3 size: " << s3.size() << endl; cout << "s3 capacity: " << s3.capacity() << endl; cout << endl; s3 = "a different string"; cout << "s3: " << s3 << endl; cout << "s3 size: " << s3.size() << endl; cout << "s3 capacity: " << s3.capacity() << endl; cout << endl; cout << "Testing self-assignment "; s3 = s3; cout << "s3: " << s3 << endl; cout << "s3 size: " << s3.size() << endl; cout << "s3 capacity: " << s3.capacity() << endl; cout << endl; cout << "Testing chained assignment "; s3 = s2 = "Hello, world"; cout << "s2: " << s2 << endl; cout << "s2 size: " << s2.size() << endl; cout << "s2 capacity: " << s2.capacity() << endl; cout << endl; cout << "s3: " << s3 << endl; cout << "s3 size: " << s3.size() << endl; cout << "s3 capacity: " << s3.capacity() << endl; cout << endl; // // Extra Credit // // This code will call the move constructor and move assignment // operator if they exist. // // If those move semantics methods are not implemented, this code // will call the copy constructor and copy assignment operator // instead. The output will be different in that case. // cout << "Extra Credit: Testing move constructor "; NIUString s6 = std::move(s5); cout << "s6: " << s6 << endl; cout << "s6 size: " << s6.size() << endl; cout << "s6 capacity: " << s6.capacity() << endl; cout << "s6 is " << ((s6.empty()) ? "empty " : "not empty "); cout << endl; cout << "s5: " << s5 << endl; cout << "s5 size: " << s5.size() << endl; cout << "s5 capacity: " << s5.capacity() << endl; cout << "s5 is " << ((s5.empty()) ? "empty " : "not empty "); cout << endl; cout << "Extra Credit: Testing move assignment operator "; s5 = std::move(s6); cout << "s5: " << s5 << endl; cout << "s5 size: " << s5.size() << endl; cout << "s5 capacity: " << s5.capacity() << endl; cout << "s5 is " << ((s5.empty()) ? "empty " : "not empty "); cout << endl; cout << "s6: " << s6 << endl; cout << "s6 size: " << s6.size() << endl; cout << "s6 capacity: " << s6.capacity() << endl; cout << "s6 is " << ((s6.empty()) ? "empty " : "not empty "); return 0; }
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started