Functions

Object Oriented Programming Functions

#include <vector>
#include <iostream>
using namespace std;

class Animal {
public:
    Animal();
    Animal(const Animal& ); //copy ctor
    Animal& operator=(const Animal& 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<<"Animal ctor"<<endl;
    agep=new int;  //call new from ctor and delete from dtor
}

Animal::Animal(const Animal& 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<<"Animal copy ctor called"<<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& Animal::operator=(const Animal& rhs){
    if (this==&rhs) return *this; //for self assignment
    *agep=*(rhs.agep);
    return *this;
}


Animal::~Animal(){ 
    cout<<"Animal dtor"<<endl;
    delete agep;   //must delete in dtor if used new in ctor
}

void Animal::noise(){
    cout<<"grr"<<endl;
}

//==============================================================

class Dog : public Animal{
public:
    Dog ();   //ctor
    Dog(const Dog& ); //copy ctor 
    Dog& operator=(const Dog& 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& operator<<(ostream& o, const Dog& 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<<"Dog ctor: There are now "<<count<< " dogs"<<endl;
}

Dog::~Dog(){
    count--;
    cout<<"Dog dtor: There are now "<<count<< " dogs"<<endl;
}

Dog::Dog(const Dog& 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<<"Copy Ctor of dog: There are now "<<count<< " dogs"<<endl;
    
}

Dog& Dog::operator=(const Dog& rhs){
    if (this==&rhs) return *this; //for self assignment
    cout<<"Dog assignment"<<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<<"ruf ruf"<<endl;
}
    
void foo(Dog f){  //copy ctor called
    cout <<"call from foo "<<*(f.agep)<<endl;
}

ostream& operator<<(ostream& o, const Dog& x){   //cout<<A<<B declared as friend of Dog class
    o<<"Age: "<<*(x.agep)<<" -- "<<"Shots: "<<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<<"the age of R is "<<*(R.agep)<<endl; //should be 5
        cout<<R<<endl;
    }
    Animal* ap=&d;
    //(*ap).noise(); //same as below
    ap->noise();     //polymorphism: Base class Animal pointer ap points to Dog object, so Dog::noise() is called
    //we can now make a vector <Animal*> v and push_back dog, cat, bird pointers.
    //if we iterate through the vector and call ->noise() we will get the correct
    //behavior ruf ruf, meow, tweet for all pointers. This is dynamic binding.

return 0;
}