#include<vector>#include<iostream>usingnamespace std;
classAnimal {
public:
Animal();
Animal(const Animal& ); //copy ctor
Animal&operator=(const Animal& rhs); //assignment operator
virtualvoidnoise(); //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=newint; //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 =newint; //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;
}
//==============================================================
classDog: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
staticint count;
bool shots;
virtualvoidnoise(); //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
}
inlinevoid Dog::noise(){ //inlining is declared in implementation or by including member function in header (compiler request:not mandatory)
cout<<"ruf ruf"<<endl;
}
voidfoo(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;
}
intmain(){
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.
return0;
}