C++ help please This is chapter pointers and classes. Client program: Data file:
ID: 639029 • Letter: C
Question
C++ help please
This is chapter pointers and classes.
Client program:
Data file:
Correct output:
See also client program, data file, and correct output.
Write a string class. To avoid conflicts with other similarly named classes, we will call our version myString. This object is designed to make working with sequences of characters a little more convenient and less error-prone than handling raw c-strings, (although it will be implemented as a c-string behind the scenes). The myString class will handle constructing strings, reading/printing, accessing characters, and some simple operators such as concatenation. In addition, the myString object will have the ability to make a full deep-copy of itself when copied.
Your class must have only one data member, a c-string implemented as a dynamic array. In particular, you must not use a data member to keep track of the size or length of the myString.
You should write the class in two phases. I've set it up this way because there are a couple of functions that are very difficult and I want to provide a way for you to skip those two functions and move on if you need to. If you submit the assignment with only phase 1 completed you can still earn almost all of the points.
Phase 1 [90 points]: Write everything except the extraction operator (>>) and the read function. To do this, you'll want to comment out that part of the client program that tests these.
Phase 2 [5 points]: The extraction operator and read() function.
Here is a list of the operations this class must support:
A length member function which returns the number of characters in the string.
Construction of a myString from a const c-string. You should copy the string data, not just store a pointer to an argument passed to the constructor. Constructing a myString with no arguments creates an empty myString object (i.e. ""). A myString object should be implemented efficiently (space-wise) which is to say you should not have a fixed-size buffer of chars, but instead allocate space for chars on an as-needed basis.
Printing a myString to a stream using an overloaded << (insertion) operator, which should simply print out its characters.
Reading into a myString from a stream using an overloaded >> (extraction) operator. The standard >> operator should skip any leading spaces and then read characters into the string to the first whitespace character.
For reasons of convenience, we will impose a limit of 127 on the number of characters this function will read. This is so you can temporarily read into a non-dynamic array and then copy what you need into your data member, which will be a dynamic array. Note that this does not mean that all myStrings will always have a maximum of 127 characters. For example, you might get a myString with more than 127 characters by using the myString constructor or by concatenating two myStrings.
Hint: use the extraction operator to do the reading of the input into a non-dynamic array, then use strcpy() to copy it into your data member.
A read() function. The read() function will allow the client programmer to specify the delimiting character (the one to stop at instead of the first space). This will be a void function that will take two arguments, a stream and the delimiting character. It should not skip leading spaces. The limit of 127 characters imposed on the >> function above also applies to this function.
Hint: use the in.getline() function to do the reading of the input into a non-dynamic array, then use strcpy() to copy it into your data member.
Your myString object should overload the square brackets [ ] operator to allow direct access to the individual characters of the string. This operation should range-check and assert if the index is out of bounds. You will write two versions of the [ ] operator, a const version that allows read access to the chars, and a non-const version that returns the client a reference to the char so they can change the value.
All six of the relational operators (<, <=, >, >=, ==, !=) should be supported. They should be able to compare myString objects to other myStrings as well as myStrings to c-strings using lexicographic ordering (i.e. strcmp). myStrings or c-strings should be able to appear on either side of the comparison operator.
The myString object should have correct "deep-copying" semantics, which is to say that when a copy of a string object is made (via the copy constructor or the operator=) the new copy should create its own copy of the string data, rather than use an alias to the character data in the original object.
myString overloads binary + to do string concatenation and the shorthand += to combine concatenation and assignment. Either myString objects or c-strings can appear on either side of the binary + or the right hand side of the +=. Only myStrings can be on the left-hand side of a += operation.
You may use all of the c-string functionality provided by C++. This will include the strlen(), strcmp(), strcpy(), strcat(), and in.getline() functions, along with the overloaded extraction and insertion operator for c-strings. These functions are all covered in detail in section 9.1 of the text. When you use strcat() and strcpy(), treat them as void functions despite the fact that they have a return value. Do not use strncpy(), strncat(), or strncmp() since they are not implemented in all versions of C++. You may NOT use anything from the C++ string class!!
You must place your header file and implementation file in a namespace. Normally one would call a namespace something more likely to be unique, but for purposes of convenience we will all call our namespace "cs2b_mystring".
Name your files mystring.h and mystring.cpp. Please comment on the header file and implementation file.
Explanation / Answer
File: mystring.h
#pragma once
#ifndef MYSTRING_H
#define MYSTRING_H
#include <iostream>
#include <cstring>
#include <cassert>
using namespace std;
namespace cs2b_mystring
{
class myString
{
friend bool operator<(const char *charArr, const myString &obj);
friend bool operator<=(const char *charArr, const myString &obj);
friend bool operator>(const char *charArr, const myString &obj);
friend bool operator>=(const char *charArr, const myString &obj);
friend bool operator==(const char *charArr, const myString &obj);
friend bool operator!=(const char *charArr, const myString &obj);
friend ostream &operator<<(ostream &out, const myString &obj);
friend istream &operator>> (istream &out, myString &obj);
friend myString operator+(const myString obj1, const myString obj2);
public:
myString();
myString(const char *charArr);
myString(const myString &obj);
~myString();
void operator=(myString &obj);
void operator=(const char *charArr);
bool operator<(const myString &obj) const;
bool operator<=(const myString &obj) const;
bool operator>(const myString &obj) const;
bool operator>=(const myString &obj) const;
bool operator==(const myString &obj) const;
bool operator!=(const myString &obj) const;
char &operator [](int index);
const char &operator[](int index) const;
int length() const;
void read(istream& ins, char delimiter);
myString& operator+=(const myString &obj);
private:
char *strPtr;
};
}
#endif
File: mystring.cpp
#include "mystring.h"
using namespace cs2b_mystring;
myString::myString()
{
strPtr = new char[1];
strPtr[0] = '';
}
myString::myString(const char *charArr)
{
int len = strlen(charArr);
strPtr = new char[len + 1];
for (int i = 0; i < len; i++)
{
strPtr[i] = charArr[i];
}
strPtr[len] = '';
}
myString::myString(const myString &obj)
{
int len = strlen(obj.strPtr);
strPtr = new char[len + 1];
for (int i = 0; i < len; ++i)
{
strPtr[i] = obj.strPtr[i];
}
strPtr[len] = '';
}
myString::~myString()
{
delete[] strPtr;
}
void myString::operator=(myString &obj)
{
if (*this != obj)
{
int len = strlen(obj.strPtr);
strPtr = new char[len + 1];
for (int i = 0; i < len; ++i)
{
strPtr[i] = obj.strPtr[i];
}
strPtr[len] = '';
}
}
void myString::operator=(const char *charArr)
{
int len = strlen(charArr);
strPtr = new char[len + 1];
for (int i = 0; i < len; ++i)
{
strPtr[i] = charArr[i];
}
strPtr[len] = '';
}
bool myString::operator<(const myString &obj) const
{
return strcmp(strPtr, obj.strPtr) < 0;
}
bool myString::operator<=(const myString &obj) const
{
return strcmp(strPtr, obj.strPtr) <= 0;
}
bool myString::operator>(const myString &obj) const
{
return strcmp(strPtr, obj.strPtr) > 0;
}
bool myString::operator>=(const myString &obj) const
{
return strcmp(strPtr, obj.strPtr) >= 0;
}
bool myString::operator==(const myString &obj) const
{
return strcmp(strPtr, obj.strPtr) == 0;
}
bool myString::operator!=(const myString &obj) const
{
return strcmp(strPtr, obj.strPtr) != 0;
}
bool cs2b_mystring::operator<(const char *charArr, const myString &obj)
{
return strcmp(charArr, obj.strPtr) < 0;
}
bool cs2b_mystring::operator<=(const char *charArr, const myString &obj)
{
return strcmp(charArr, obj.strPtr) <= 0;
}
bool cs2b_mystring::operator>(const char *charArr, const myString &obj)
{
return strcmp(charArr, obj.strPtr) > 0;
}
bool cs2b_mystring::operator>=(const char *charArr, const myString &obj)
{
return strcmp(charArr, obj.strPtr) >= 0;
}
bool cs2b_mystring::operator==(const char *charArr, const myString &obj)
{
return strcmp(charArr, obj.strPtr) == 0;
}
bool cs2b_mystring::operator!=(const char *charArr, const myString &obj)
{
return strcmp(charArr, obj.strPtr) != 0;
}
ostream &cs2b_mystring::operator<<(ostream &out, const myString &obj)
{
out << obj.strPtr;
return out;
}
istream &cs2b_mystring::operator>>(istream &in, myString &obj)
{
in >> obj.strPtr;
return in;
}
char& myString::operator [](int i)
{
int len = strlen(strPtr);
assert(0 <= i && i < len);
return strPtr[i];
}
const char& myString::operator[](int i) const
{
int len = strlen(strPtr);
assert(0 <= i && i < len);
return strPtr[i];
}
int myString::length() const
{
return strlen(strPtr);
}
void myString::read(istream &ins, char delimiter)
{
char tempArr[128];
delete[] strPtr;
ins.getline(tempArr, 127, delimiter);
strcpy(strPtr, tempArr);
}
myString cs2b_mystring::operator+(const myString obj1, const myString obj2)
{
myString tempObj;
tempObj.strPtr = new char[strlen(obj1.strPtr) + strlen(obj2.strPtr) + 1];
strcat(obj1.strPtr, obj2.strPtr);
strcpy(tempObj.strPtr, obj1.strPtr);
return tempObj;
}
myString& myString::operator+=(const myString &obj)
{
*this = *this + obj;
return *this;
}
File: main.cpp
#include "mystring.h"
#include <fstream>
#include <cctype> // for toupper()
#include <string> // for strchr(), strstr(), etc.
#include <cassert>
#include <iostream>
using namespace std;
using namespace cs2b_mystring;
bool eof(istream& in);
void BasicTest();
void RelationTest();
void ConcatTest();
void CopyTest();
myString AppendTest(const myString& ref, myString val);
int main()
{
BasicTest();
RelationTest();
ConcatTest();
CopyTest();
return 0;
}
bool eof(istream& in)
{
char ch;
in >> ch;
in.putback(ch);
return !in;
}
void BasicTest()
{
myString s;
cout << "----- Testing basic String creation & printing" << endl;
const myString strs[] =
{ myString("Wow"), myString("C++ is neat!"),
myString(""), myString("a-z") };
for (int i = 0; i < 4; i++) {
cout << "string [" << i << "] = " << strs[i] << endl;
}
cout << endl << "----- Now reading myStrings from file" << endl;
cout << endl << "----- first, word by word" << endl;
ifstream in("string.data");
assert(in);
while (in.peek() == '#') {
in.ignore(128, ' ');
}
in >> s;
while (in) {
cout << "Read string = " << s << endl;
in >> s;
}
in.close();
cout << endl << "----- now, line by line" << endl;
ifstream in2("string.data");
assert(in2);
while (in2.peek() == '#') {
in2.ignore(128, ' ');
}
s.read(in2, ' ');
while (in2) {
cout << "Read string = " << s << endl;
s.read(in2, ' ');
}
cout << endl << "----- Testing access to characters (using const)" << endl;
const myString s1("abcdefghijklmnopqsrtuvwxyz");
cout << "Whole string is " << s1 << endl;
cout << "now char by char: ";
for (int i = 0; i < s1.length(); i++) {
cout << s1[i];
}
cout << endl << "----- Testing access to characters (using non-const)" << endl;
myString s2("abcdefghijklmnopqsrtuvwxyz");
cout << "Start with " << s2;
for (int i = 0; i < s2.length(); i++) {
s2[i] = toupper(s2[i]);
}
cout << " and convert to " << s2 << endl;
}
void RelationTest()
{
cout << " ----- Testing relational operators between myStrings ";
const myString strs[] =
{ myString("app"), myString("apple"), myString(""),
myString("Banana"), myString("Banana") };
for (int i = 0; i < 4; i++) {
cout << "Comparing " << strs[i] << " to " << strs[i + 1] << endl;
cout << " Is left < right? " << (strs[i] < strs[i + 1]) << endl;
cout << " Is left <= right? " << (strs[i] <= strs[i + 1]) << endl;
cout << " Is left > right? " << (strs[i] > strs[i + 1]) << endl;
cout << " Is left >= right? " << (strs[i] >= strs[i + 1]) << endl;
cout << " Does left == right? " << (strs[i] == strs[i + 1]) << endl;
cout << " Does left != right ? " << (strs[i] != strs[i + 1]) << endl;
}
cout << " ----- Testing relations between myStrings and char * ";
myString s("he");
const char *t = "hello";
cout << "Comparing " << s << " to " << t << endl;
cout << " Is left < right? " << (s < t) << endl;
cout << " Is left <= right? " << (s <= t) << endl;
cout << " Is left > right? " << (s > t) << endl;
cout << " Is left >= right? " << (s >= t) << endl;
cout << " Does left == right? " << (s == t) << endl;
cout << " Does left != right ? " << (s != t) << endl;
myString u("wackity");
const char *v = "why";
cout << "Comparing " << v << " to " << u << endl;
cout << " Is left < right? " << (v < u) << endl;
cout << " Is left <= right? " << (v <= u) << endl;
cout << " Is left > right? " << (v > u) << endl;
cout << " Is left >= right? " << (v >= u) << endl;
cout << " Does left == right? " << (v == u) << endl;
cout << " Does left != right ? " << (v != u) << endl;
}
void ConcatTest()
{
cout << " ----- Testing concatentation on myStrings ";
const myString s[] =
{ myString("outrageous"), myString("milk"), myString(""),
myString("cow"), myString("bell") };
for (int i = 0; i < 4; i++) {
cout << s[i] << " + " << s[i + 1] << " = " << s[i] + s[i + 1] << endl;
}
cout << " ----- Testing concatentation between myString and char * ";
const myString a("abcde");
const char *b = "XYZ";
cout << a << " + " << b << " = " << a + b << endl;
cout << b << " + " << a << " = " << b + a << endl;
cout << " ----- Testing shorthand concat/assign on myStrings ";
myString s2[] =
{ myString("who"), myString("what"), myString("WHEN"),
myString("Where"), myString("why") };
for (int i = 0; i < 4; i++) {
cout << s2[i] << " += " << s2[i + 1] << " = ";
cout << (s2[i] += s2[i + 1]) << endl;
}
cout << " ----- Testing shorthand concat/assign using char * ";
myString u("I love ");
const char *v = "programming";
cout << u << " += " << v << " = ";
cout << (u += v) << endl;
}
myString AppendTest(const myString& ref, myString val)
{
val[0] = 'B';
return val + ref;
}
void CopyTest()
{
cout << " ----- Testing copy constructor and operator= on myStrings ";
myString orig("cake");
myString copy(orig); // invoke copy constructor
copy[0] = 'f'; // change first letter of the *copy*
cout << "original is " << orig << ", copy is " << copy << endl;
myString copy2; // makes an empty string
copy2 = orig; // invoke operator=
copy2[0] = 'f'; // change first letter of the *copy*
cout << "original is " << orig << ", copy is " << copy2 << endl;
copy2 = "Copy Cat";
copy2 = copy2; // copy onto self and see what happens
cout << "after self assignment, copy is " << copy2 << endl;
cout << "Testing pass & return myStrings by value and ref" << endl;
myString val = "winky";
myString sum = AppendTest("Boo", val);
cout << "after calling Append, sum is " << sum << endl;
cout << "val is " << val << endl;
val = sum;
cout << "after assign, val is " << val << endl;
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.