<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>OOP :: CS3 course</title><link>https://robark.gitlab.io/oop/index.html</link><description>Object Oriented Programming Create a String Class</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Tue, 16 May 2023 10:36:57 -0700</lastBuildDate><atom:link href="https://robark.gitlab.io/oop/index.xml" rel="self" type="application/rss+xml"/><item><title>Mystring</title><link>https://robark.gitlab.io/oop/mystring/index.html</link><pubDate>Tue, 17 May 2022 23:52:53 +0000</pubDate><guid>https://robark.gitlab.io/oop/mystring/index.html</guid><description>Mystring class Example of rule of three. Must include copy ctor, destructor and assignment operator for classes that use dynamic memory on the heap.
#include &lt;iostream&gt; using namespace std; class mystring{ private: char* _s; size_t _len; friend ostream&amp; operator&lt;&lt;(ostream &amp;, const mystring&amp; ); public: mystring(); ~mystring(); mystring(const char*); mystring(const mystring&amp;); //copy ctor size_t length() const; mystring&amp; operator=(const mystring&amp;); mystring&amp; operator=(const char*); }; //helper functions //======================= ostream&amp; operator&lt;&lt;(ostream &amp;o, const mystring &amp;ms){ //friend for (size_t x=0; x&lt;ms._len ; x++) o &lt;&lt; ms._s[x]; return o; } size_t mystrlen(const char* cstr){ size_t x=0; while (cstr[x] != '\0') x++; return x; } //======================== //member functions //======================== mystring::mystring(){ _s= nullptr; _len=0; } mystring::~mystring(){ delete[] _s; } mystring::mystring(const char* st ){ //overloaded ctor size_t size = mystrlen(st); //helper function _s= new char[size]; for (size_t x=0; x&lt;size ; x++) _s[x]=st[x]; _len=size; } mystring::mystring(const mystring&amp; ms){ //copy ctor _s = new char[ ms.length() ]; for (size_t x=0; x&lt;ms.length(); x++) _s[x] = ms._s[x]; _len=ms.length(); } size_t mystring::length() const{ return _len; } mystring&amp; mystring::operator=(const mystring &amp;ms){ delete[] _s; _s = new char[ ms.length() ]; for (size_t x=0; x&lt;ms.length(); x++) _s[x] = ms._s[x]; _len=ms.length(); return *this; } mystring&amp; mystring::operator=(const char* st){ delete[] _s; size_t size = mystrlen(st); _s= new char[size]; for (size_t x=0; x&lt;size ; x++) _s[x] = st[x]; _len=size; return *this; } //============================================== mystring foo(mystring b){ mystring d; d=b; return d; //copy ctor called } //d is deleted int main(){ mystring b; b="world"; cout&lt;&lt;b&lt;&lt;endl; if (1) { mystring a("hello"); b=a; //operator= required } // a gets destroyed cout&lt;&lt;b&lt;&lt;endl; cout&lt;&lt;foo(b)&lt;&lt;endl; //copy ctor required or double free return 0; }</description></item><item><title>Functions</title><link>https://robark.gitlab.io/oop/functions/index.html</link><pubDate>Tue, 16 May 2023 10:36:57 -0700</pubDate><guid>https://robark.gitlab.io/oop/functions/index.html</guid><description>Object Oriented Programming Functions #include &lt;vector&gt; #include &lt;iostream&gt; using namespace std; class Animal { public: Animal(); Animal(const Animal&amp; ); //copy ctor Animal&amp; operator=(const Animal&amp; rhs); //assignment operator virtual void noise(); //virtual so we can overload in subclass and use polymorphism int* agep; virtual ~Animal(); //destructor must be virtual and must exist even if empty }; Animal::Animal(){ cout&lt;&lt;"Animal ctor"&lt;&lt;endl; agep=new int; //call new from ctor and delete from dtor } Animal::Animal(const Animal&amp; x){ //copy ctor //agep=x.agep; //happens by default - not good - shallow copy (causes memory leak AND calling delete twice which is undefined behavior) cout&lt;&lt;"Animal copy ctor called"&lt;&lt;endl; agep =new int; //since agep in base class, call new int here. Therefore, call base class copy ctor from sub class (Dog) copy ctor *agep=*(x.agep); //deep copy } Animal&amp; Animal::operator=(const Animal&amp; rhs){ if (this==&amp;rhs) return *this; //for self assignment *agep=*(rhs.agep); return *this; } Animal::~Animal(){ cout&lt;&lt;"Animal dtor"&lt;&lt;endl; delete agep; //must delete in dtor if used new in ctor } void Animal::noise(){ cout&lt;&lt;"grr"&lt;&lt;endl; } //============================================================== class Dog : public Animal{ public: Dog (); //ctor Dog(const Dog&amp; ); //copy ctor Dog&amp; operator=(const Dog&amp; rhs); virtual ~Dog (); //dtor is virtual whether we declare it to be or not since base class dtor is virtual static int count; bool shots; virtual void noise(); //no inline declaration in header is virtual cause base class noise virtual friend ostream&amp; operator&lt;&lt;(ostream&amp; o, const Dog&amp; x); }; int Dog::count=0; //must initialize static members at file scope Dog::Dog():shots(false){ count++; //shots=false; //same as using initialization list above. If shots was const must use init list cout&lt;&lt;"Dog ctor: There are now "&lt;&lt;count&lt;&lt; " dogs"&lt;&lt;endl; } Dog::~Dog(){ count--; cout&lt;&lt;"Dog dtor: There are now "&lt;&lt;count&lt;&lt; " dogs"&lt;&lt;endl; } Dog::Dog(const Dog&amp; d):Animal(d){ // Dog copy ctor calls ctor of Dog but Dog ctor calls base class ctor first //agep=x.agep; //happens by default shallow copy //agep=new int; //wrong since agep is part of base class let base class handle memory allocation //*agep=*(x.agep); //wrong because agep is part of base class. Instead call Animal copy ctor from init list :Animal(x) above shots=d.shots; //correct shots is only part of Dog count++; cout&lt;&lt;"Copy Ctor of dog: There are now "&lt;&lt;count&lt;&lt; " dogs"&lt;&lt;endl; } Dog&amp; Dog::operator=(const Dog&amp; rhs){ if (this==&amp;rhs) return *this; //for self assignment cout&lt;&lt;"Dog assignment"&lt;&lt;endl; Animal::operator=(rhs); //explicitly call Animal assignment operator sending rhs by reference shots=rhs.shots; return *this; //so multiple assignment will work eg a=b=c } inline void Dog::noise(){ //inlining is declared in implementation or by including member function in header (compiler request:not mandatory) cout&lt;&lt;"ruf ruf"&lt;&lt;endl; } void foo(Dog f){ //copy ctor called cout &lt;&lt;"call from foo "&lt;&lt;*(f.agep)&lt;&lt;endl; } ostream&amp; operator&lt;&lt;(ostream&amp; o, const Dog&amp; x){ //cout&lt;&lt;A&lt;&lt;B declared as friend of Dog class o&lt;&lt;"Age: "&lt;&lt;*(x.agep)&lt;&lt;" -- "&lt;&lt;"Shots: "&lt;&lt;x.shots; return o; } int main(){ Dog d; //stack *(d.agep)=5; foo(d); //copy ctor called since copy-by-value is default in C++ if (1){ Dog R; R=d; //needs overloaded operator= //cout&lt;&lt;"the age of R is "&lt;&lt;*(R.agep)&lt;&lt;endl; //should be 5 cout&lt;&lt;R&lt;&lt;endl; } Animal* ap=&amp;d; //(*ap).noise(); //same as below ap-&gt;noise(); //polymorphism: Base class Animal pointer ap points to Dog object, so Dog::noise() is called //we can now make a vector &lt;Animal*&gt; v and push_back dog, cat, bird pointers. //if we iterate through the vector and call -&gt;noise() we will get the correct //behavior ruf ruf, meow, tweet for all pointers. This is dynamic binding. return 0; }</description></item></channel></rss>