summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--main.cpp18
-rw-r--r--string.cpp61
-rw-r--r--string.h27
3 files changed, 73 insertions, 33 deletions
diff --git a/main.cpp b/main.cpp
index dd4810d..607b40c 100644
--- a/main.cpp
+++ b/main.cpp
@@ -10,9 +10,13 @@ int main(int argc, char **argv)
else
std::cout << "false" << std::endl;
+ /* uses copy ctor, compiler implicitly creates obj out of ", beta" and
+ * then passess it to copy ctor
+ */
MyString mystr1 = ", beta";
- MyString mystr2 = ", charlie";
- MyString mystr3 = ", delta";
+ /* next to call ctor that takes in char arr */
+ MyString mystr2("charlie"); /* if it was () then it would be a fwd decl! */
+ MyString mystr3 = MyString(", delta");
mystr.concat(mystr1).concat(mystr2).concat(mystr3);
std::cout << mystr << std::endl;
@@ -21,9 +25,17 @@ int main(int argc, char **argv)
mystr4.concat(", world!").concat(" goodbye");
std::cout << mystr4 << std::endl;
+ /* test outward conversion */
+ const char *mystr_charptr = mystr4;
+ std::cout << mystr_charptr << " | len: " << std::strlen(mystr_charptr) << std::endl;
+
MyString mystr5 = "bro";
std::cout << mystr5 << ", char at 1 is: " << mystr5[1] << std::endl;
+ /* getCount() is a static method hence it doesn't need to be called on
+ * an object
+ */
+ std::cout << "mystring instances count: " << MyString::getCount();
+
return 0;
}
-
diff --git a/string.cpp b/string.cpp
index 42e97cc..e75b50e 100644
--- a/string.cpp
+++ b/string.cpp
@@ -9,23 +9,41 @@
MyString::MyString(int len) : str_(new char[len + 1]), length_(len)
{
+ this->count++;
}
-MyString::MyString(const char *str) : length_(strlen(str))
+MyString::MyString(const char *str) : str_(new char[strlen(str)+1]), length_(strlen(str))
{
- str_ = new char[length_ + 1];
strcpy(str_, str);
+ this->count++;
}
MyString::MyString(const MyString& str) : str_(new char[str.length_ + 1]),
length_(str.length_)
{
strcpy(str_, str.str_);
+ this->count++;
+}
+
+MyString& MyString::operator=(const MyString& rhs)
+{
+ /* don't do anything if object assigns itself */
+ if (this == &rhs)
+ return *this;
+
+ length_ = rhs.length_;
+ delete[] str_;
+ str_ = new char[ length_ + 1];
+ strcpy(str_, rhs.str_);
+
+ /* assignment operator requires this */
+ return *this;
}
MyString::~MyString()
{
delete[] str_;
+ this->count--;
}
int MyString::indexOf(char ch, int pos) const
@@ -41,6 +59,9 @@ int MyString::indexOf(char ch, int pos) const
return -1;
}
+/* define this field only once, .h is not the best place */
+size_t MyString::count = 0;
+
bool MyString::isSubstring(const MyString& str) const
{
if (length_ < str.length_)
@@ -65,6 +86,9 @@ bool MyString::isSubstring(const MyString& str) const
return false;
}
+/* might seem redundant since constructor can create an object from char array
+ * and call other isSubstring method that takes in MyString type
+ */
bool MyString::isSubstring(const char *str) const
{
int i, j, k;
@@ -109,21 +133,6 @@ MyString& MyString::concat(const char *str)
return *this;
}
-MyString& MyString::operator=(const MyString& rhs)
-{
- /* don't do anything if object assigns itself */
- if (this == &rhs)
- return *this;
-
- length_ = rhs.length_;
- delete[] str_;
- str_ = new char[ length_ + 1];
- strcpy(str_, rhs.str_);
-
- /* assignment operator requires this */
- return *this;
-}
-
bool operator==(const MyString& lhs, const MyString& rhs)
{
if (lhs.length_ != rhs.length_)
@@ -135,13 +144,17 @@ bool operator==(const MyString& lhs, const MyString& rhs)
return false;
}
-/* seems like the ostream& in front has nothing to do with dereferencing a pointer,
- * but it seems like the & is placed there so we can make consecutive overloaded
- * calls to cout, effectively chaining all of the calls
- */
+bool operator!=(const MyString& lhs, const MyString& rhs)
+{
+ return !(lhs == rhs);
+}
/* right now I think the reference is used to avoid returning copy of ostream
- * so when calls are chained up we work on one ostream object only */
+ * so when calls are chained up we work on one ostream object only
+ *
+ * this function is in global scope, it is friend'ed to allow us access to data
+ * members of calss MyString
+ */
std::ostream& operator<<(std::ostream& ostr, const MyString& rhs)
{
return (ostr << rhs.str_);
@@ -179,3 +192,7 @@ MyString::operator char*()
return NULL;
}
+MyString::operator const char*() const
+{
+ return this->str_;
+}
diff --git a/string.h b/string.h
index dbc8e88..2e86086 100644
--- a/string.h
+++ b/string.h
@@ -17,11 +17,14 @@ class MyString
char *str_;
int length_;
MyString(int);
+ static size_t count;
public:
MyString();
- MyString(char);
+ explicit MyString(char);
+ /* allow implicit conversions, it is useful */
MyString(const char *);
+ /* copy constructor */
MyString(const MyString &);
MyString& operator=(const MyString &);
~MyString();
@@ -33,29 +36,33 @@ class MyString
MyString& concat(const MyString &);
MyString& concat(const char *);
void printStr(void) const;
+ static size_t getCount(void);
bool operator!(void) const;
char& operator[](int);
char operator[](int) const;
operator char*(); /* outward class conversion into char * */
+ operator const char*() const;
};
bool operator==(const MyString&, const MyString &);
+bool operator!=(const MyString&, const MyString &);
std::ostream& operator<<(std::ostream&, const MyString &);
-inline MyString::MyString()
+/* it is always good idea to have default ctor to avoid manual init later
+ * for data types that include this class type
+ */
+inline MyString::MyString() : str_(new char[1]), length_(0)
{
- length_ = 0;
- str_ = new char[1];
str_[0] = '\0';
+ this->count++;
}
-inline MyString::MyString(char ch)
+inline MyString::MyString(char ch) : str_(new char[2]), length_(1)
{
- length_ = 1;
- str_ = new char[2];
str_[0] = ch;
str_[1] = '\0';
+ this->count++;
}
inline int MyString::length() const
@@ -68,5 +75,9 @@ inline void MyString::printStr(void) const
std::cout << "length: " << length_ << ", value: \"" << str_ << "\"";
}
-#endif
+inline size_t MyString::getCount(void)
+{
+ return count;
+}
+#endif