In: Computer Science
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 <iostream> #include "NIUString.h" using std::cout; using std::endl; int main() { cout << "Testing default constructor\n\n"; 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\n" : "not empty\n"); cout << endl; cout << "Testing second constructor\n\n"; 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\n" : "not empty\n"); cout << endl; cout << "Testing second constructor with long string\n\n"; 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\n\n"; s2[0] = 'S'; s2[5] = 'T'; cout << "s2: " << s2 << endl << endl; cout << "Testing read form of subscript operator\n\n"; cout << "s2: "; for (size_t i = 0; i < s2.size(); i++) cout << s2[i]; cout << endl << endl; cout << "Testing reserve() method\n\n"; 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\n" : "not empty\n"); 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\n" : "not empty\n"); 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\n" : "not empty\n"); 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\n" : "not empty\n"); cout << endl; cout << "Testing equality operators\n\n"; const NIUString s4 = "Some Text"; cout << "s2 and s4 are " << ((s2 == s4) ? "equal\n" : "not equal\n"); cout << "s3 and s4 are " << ((s3 == s4) ? "equal\n" : "not equal\n\n"); cout << "s4 and \"Some Text\" are " << ((s4 == "Some Text") ? "equal\n" : "not equal\n"); cout << "s4 and \"More Text\" are " << ((s4 == "More Text") ? "equal\n" : "not equal\n\n"); cout << "\"Some Text\" and s4 are " << (("Some Text" == s4) ? "equal\n" : "not equal\n"); cout << "\"More Text\" and s4 are " << (("More Text" == s4) ? "equal\n" : "not equal\n\n"); cout << "Testing clear() method\n\n"; s3.clear(); cout << "s3: " << s3 << endl; cout << "s3 size: " << s3.size() << endl; cout << "s3 capacity: " << s3.capacity() << endl; cout << "s3 is " << ((s3.empty()) ? "empty\n" : "not empty\n"); cout << endl; cout << "Testing copy constructor\n\n"; 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\n\n"; 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\n\n"; s3 = s3; cout << "s3: " << s3 << endl; cout << "s3 size: " << s3.size() << endl; cout << "s3 capacity: " << s3.capacity() << endl; cout << endl; cout << "Testing chained assignment\n\n"; 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\n\n"; 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\n" : "not empty\n"); cout << endl; cout << "s5: " << s5 << endl; cout << "s5 size: " << s5.size() << endl; cout << "s5 capacity: " << s5.capacity() << endl; cout << "s5 is " << ((s5.empty()) ? "empty\n" : "not empty\n"); cout << endl; cout << "Extra Credit: Testing move assignment operator\n\n"; 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\n" : "not empty\n"); cout << endl; cout << "s6: " << s6 << endl; cout << "s6 size: " << s6.size() << endl; cout << "s6 capacity: " << s6.capacity() << endl; cout << "s6 is " << ((s6.empty()) ? "empty\n" : "not empty\n"); return 0; }
Note: Please save all the files as per the below project.
Program Screenshots:
Sample Output:
Code to be Copied:
NIUString.h
#pragma once
#ifndef NIUSTRING_H
//nclude required header files
#include <cstdlib>
#include <iostream>
using std::ostream;
//declare class
class NIUString {
//Prints contents of object's char array
friend ostream& operator<<(ostream&,
const NIUString&);
//Compares a string and string of an object
friend bool operator==(const char*, const
NIUString&);
//member functions
public:
//Default Constructor
NIUString();
//parameterized Constructor
NIUString(const char*);
//Copy Constructor
NIUString(const NIUString&);
//Move Constructor
NIUString(NIUString&&);
//Move assignment overload
NIUString& operator=(NIUString&&);
//Class Destructor
~NIUString();
//Accessor methods
//Returns capacity of string array
size_t capacity() const;
//Returns size of string array
size_t size() const;
//Check whether if string is empty
bool empty() const;
//Delete dynamically allocated
//memory
void
clear();
//Changes string capacity only
void
reserve(size_t);
//Overload == operator
bool operator==(const NIUString&) const;
//Overload == operator
bool operator==(const char*)
const;
//Overload subscript operator
const char& operator[](size_t) const;
//Overload subscript operator
char&
operator[](size_t);
//Overload assignment operator
NIUString& operator=(const
NIUString&);
//Overload assignment operator
NIUString& operator=(const
char*);
//private variables
private:
//Dynamically allocated string array
char* array;
//String capacity
size_t strCap;
//String size
size_t strSize;
};
#endif
NIUString.cpp
//include header files
#include "NIUString.h"
NIUString::NIUString()
{
//Initialize data members
//to empty/default status
strSize = 0;
strCap = 0;
array = nullptr;
}
//Parameterized constructor
NIUString::NIUString(const char* other)
{
//Counts number of characters in parameter
string
int cnt = 0;
while (other[cnt] != 0)
cnt++;
//Sets string size data member to
//number of charecters in parameter string
strSize = cnt;
//Sets string capacity data member to string
size
strCap = strSize;
//If parameter string has no charecters,
//sets object's string array pointer to null.
if (strCap == 0)
array = nullptr;
//Otherwise, dynamically allocates
//enough mem to hold parameter string
else
array = new char[strCap];
//Loop to copy each element of
//parameter string to object's string array
for (size_t i = 0; i < strSize; i++)
{
array[i] = other[i];
}
}
//Implement the copy constructor method
NIUString::NIUString(const NIUString& other)
{
strSize = other.strSize;
strCap =
other.strCap;
if (strCap == 0)
{
array = nullptr;
}
else
{
array = new char[strCap];
}
//Loop to copy parameter object's
//string array to calling object's string array
for (size_t i = 0; i < strSize; i++)
{
array[i] = other.array[i];
}
}
//Implement destructor method
NIUString::~NIUString()
{
clear();
}
//Implement overload operator
NIUString& NIUString::operator=(const NIUString&
other)
{
//Checks for self assignment
if (this != &other)
{
////Deallocates memory pointed to
by string array of calling object
delete[]
this->array;
this->strSize =
other.strSize;
this->strCap = other.strCap;
//Sets calling object's
string
//array pointer to null for empty
string
if (this->strCap == 0)
array =
nullptr;
//Otherwise, Dynamically
allocates
//enough memory to hold parameter
object's string array
else
this->array =
new char[this->strCap];
//Loop to copy parameter
//object's string array to calling
object
for (size_t i = 0; i <
this->strSize; i++)
{
this->array[i] = other.array[i];
}
}
return *this;
}
//Implement overloaded operator method
NIUString& NIUString::operator=(const char* other)
{
//Deallocates memory pointed to by string array of
calling object
delete[] this->array;
//Counts number of characters in parameter
string
int count = 0;
while (other[count] != 0)
count++;
//Assigns calling objects size to size of parameter
string
this->strSize = count;
//String cap is same as string size
this->strCap = this->strSize;
//Sets array to nullptr if parameter string is
empty
if (this->strCap == 0)
this->array = nullptr;
//Otherwise, dynamically allocates
//enough memory to hold number of charecters in
parameter string
else
this->array = new
char[this->strCap];
//Loop to copy parameter string
//array to calling object's string array
for (size_t i = 0; i < this->strSize; i++)
{
this->array[i] = other[i];
}
return *this;
}
//Implement method to return the capacity of array
size_t NIUString::capacity() const
{
return strCap;
}
//Implement method to return the size of array
size_t NIUString::size() const
{
return strSize;
}
//Implement method to empty the array
bool NIUString::empty() const
{
//Checks size of string to determine if empty
if (strSize == 0)
return true;
else
return false;
}
//Implement clear method
void NIUString::clear()
{
strSize = 0;
strCap = 0;
delete[] array;
array = nullptr;
}
//Does nothing if n is less than/equal to string size or equal to
string cap
//Otherwise changes string capacity
void NIUString::reserve(size_t n)
{
//Sets string capacity to parameter n
if (n > strSize && n != strCap)
{
strCap =
n;
//Temporary pointer to a char
char* tempPtr;
//Sets tempPtr to nullptr if
parameter n is zero
if (strCap == 0)
tempPtr =
nullptr;
//Otherwise, dynamically
allocates
//enough memory to hold n
characters
else
tempPtr = new
char[strCap];
//Loop to copy string array of
calling object to temp array
for (size_t i = 0; i < strSize;
i++)
{
tempPtr[i] =
array[i];
}
//Deallocates dynamic memory used
for string array
delete[] array;
//Sets string array pointer to
temporary array pointer
array = tempPtr;
}
}
//Implement overload operator method
bool NIUString::operator==(const NIUString& rhs) const
{
//Checks if strings are different sizes
if (strSize != rhs.strSize)
return false;
//Otherwise, compares each respective element
//of the parameters string arrays
else
{
//Loop to compare each charecter of
string
//in parameter object and calling
object
//Returns false if a charecter is
found to be different
for (size_t i = 0; i < strSize;
i++)
{
if (array[i] !=
rhs.array[i])
{
return false;
}
}
//Passed compare loop, therefore
both are same
return true;
}
}
//Iplement overload operatot
bool NIUString::operator==(const char* other) const
{
//Counts number of characters in parameter
string
size_t count = 0;
while (other[count] != 0)
count++;
//Checks if strings are different sizes
if (strSize != count)
return false;
//Otherwise, compares each respective element of
the string arrays
else
{
//Loop to compare each charecter in
parameter string and calling object
//Returns false if a charecter is
found to be different
for (size_t i = 0; i < strSize;
i++)
{
if (array[i] !=
other[i])
{
return false;
}
}
return true; //Passed
compare loop, therefore both are same
}
}
const char& NIUString::operator[](size_t pos) const
{
return array[pos];
}
char& NIUString::operator[](size_t pos)
{
return array[pos];
}
ostream& operator<<(ostream& lhs, const
NIUString& rhs)
{
//Loops through each element of array
for (size_t i = 0; i < rhs.strSize; i++)
{
//Cascades output to stream
object
lhs << rhs.array[i];
}
return lhs;
//Returns output stream object
}
bool operator==(const char* lhs, const NIUString& rhs)
{
//Counts number of charecters in lhs parameter
size_t count = 0;
while (lhs[count] != 0)
count++;
//Compares string sizes of lhs and rhs parameters,
false if different
if (rhs.strSize != count)
return false;
//Otherwise, compares each respective element of
the parameters string array
else
{
//Loop to compare each charecter of
parameters string array
//Returns false if different
for (size_t i = 0; i <
rhs.strSize; i++)
{
if (lhs[i] !=
rhs.array[i])
{
return false;
}
}
return true; //Passed
compare loop, therefore both are same
}
}
NIUString::NIUString(NIUString&& other) : array(NULL),
strCap(0), strSize(0)
{
//Assigns class data members from source object to the
one being constructed
strSize = other.strSize;
strCap = other.strCap;
array = other.array;
//Sets source object to default status
other.strSize = 0;
other.strCap = 0;
other.array = nullptr;
}
NIUString& NIUString::operator=(NIUString&&
other)
{
//Checks for self assignment
if (this != &other)
{
//Delete existing dyanmic memory of
calling objects string array
delete[]
array;
//Assigns class data members
from source object to calling object
strSize = other.strSize;
strCap = other.strCap;
array = other.array;
//Sets source object to default
status
other.strSize = 0;
other.strCap = 0;
other.array = nullptr;
}
return *this;
}
main.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 <iostream>
#include "NIUString.h"
using std::cout;
using std::endl;
int main()
{
cout << "Testing default constructor\n\n";
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\n" : "not empty\n");
cout << endl;
cout << "Testing second constructor\n\n";
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\n" : "not empty\n");
cout << endl;
cout << "Testing second constructor with long string\n\n";
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\n\n";
s2[0] = 'S';
s2[5] = 'T';
cout << "s2: " << s2 << endl
<< endl;
cout << "Testing read form of subscript operator\n\n";
cout << "s2: ";
for (size_t i = 0; i < s2.size(); i++)
cout << s2[i];
cout << endl << endl;
cout << "Testing reserve() method\n\n";
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\n" : "not empty\n");
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\n" : "not empty\n");
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\n" : "not empty\n");
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\n" : "not empty\n");
cout << endl;
cout << "Testing equality operators\n\n";
const NIUString s4 = "Some Text";
cout << "s2 and s4 are " << ((s2 == s4)
? "equal\n" : "not equal\n");
cout << "s3 and s4 are " << ((s3 == s4) ?
"equal\n" : "not equal\n\n");
cout << "s4 and \"Some Text\" are " <<
((s4 == "Some Text") ? "equal\n" : "not equal\n");
cout << "s4 and \"More Text\" are " <<
((s4 == "More Text") ? "equal\n" : "not equal\n\n");
cout << "\"Some Text\" and s4 are " <<
(("Some Text" == s4) ? "equal\n" : "not equal\n");
cout << "\"More Text\" and s4 are " <<
(("More Text" == s4) ? "equal\n" : "not equal\n\n");
cout << "Testing clear() method\n\n";
s3.clear();
cout << "s3: " << s3 <<
endl;
cout << "s3 size: " << s3.size() <<
endl;
cout << "s3 capacity: " << s3.capacity()
<< endl;
cout << "s3 is " << ((s3.empty()) ?
"empty\n" : "not empty\n");
cout << endl;
cout << "Testing copy constructor\n\n";
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\n\n";
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\n\n";
s3 = s3;
cout << "s3: " << s3 <<
endl;
cout << "s3 size: " << s3.size() <<
endl;
cout << "s3 capacity: " << s3.capacity()
<< endl;
cout << endl;
cout << "Testing chained assignment\n\n";
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\n\n";
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\n" : "not empty\n");
cout << endl;
cout << "s5: " << s5 <<
endl;
cout << "s5 size: " << s5.size() <<
endl;
cout << "s5 capacity: " << s5.capacity()
<< endl;
cout << "s5 is " << ((s5.empty()) ?
"empty\n" : "not empty\n");
cout << endl;
cout << "Extra Credit: Testing move assignment operator\n\n";
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\n" : "not empty\n");
cout << endl;
cout << "s6: " << s6 <<
endl;
cout << "s6 size: " << s6.size() <<
endl;
cout << "s6 capacity: " << s6.capacity()
<< endl;
cout << "s6 is " << ((s6.empty()) ?
"empty\n" : "not empty\n");
return 0;
}