// MT4Q1.cpp #include class B { public: B() { std::cout << "\n default construction of B"; } B(const B& b) { std::cout << "\n copy construction of B"; } B& operator=(const B& b) { std::cout << "\n assigning B"; if(this == &b) return *this; // if there were data members, assign them here return *this; } virtual ~B() { std::cout << "\n destroying B"; } void say() const { std::cout << "\n B here"; } }; class C { public: C(double val=0) : val_(val) { std::cout << "\n default construction of C"; } C(const C& c) : val_(c.val_) { std::cout << "\n copy construction of C"; } C& operator=(const C& c) { std::cout << "\n assigning C"; if(this == &c) return *this; val_ = c.val_; return *this; } ~C() { std::cout << "\n destroying C"; } void say() const { std::cout << "\n C here"; std::cout << "\n my value is " << value(); } double& value() { return val_; } double value() const { return val_; } private: double val_; }; class U { public: U() { std::cout << "\n default construction of U"; } U(const U& u) { std::cout << "\n copy construction of U"; } ~U() { std::cout << "\n destroying U"; } void say() const { std::cout << "\n U here"; } }; class D : public B { public: D() { std::cout << "\n default construction of D"; } D(const D& d) : B(d), c(d.c) { std::cout << "\n copy construction of D"; }; D& operator=(const D& d) { std::cout << "\n assigning D"; if(this == &d) return *this; static_cast(*this) = d; //B::operator =(d); // this works and is a suitable alternative //(B&)*this = d; // this also works, but prefer the static_cast c = d.c; return *this; } ~D() { std::cout << "\n destroying D"; } void say(const U& u) const { std::cout << "\n D here"; c.say(); u.say(); } double& value() { return c.value(); } private: C c; }; class modD : public B { public: modD() : pC(0) { std::cout << "\n default construction of modD"; } modD(const modD& md) : B(md) { std::cout << "\n copy construction of modD"; if(md.pC != 0) pC = new C(*md.pC); else pC = 0; }; void createC(double val) { pC = new C(val); } modD& operator=(const modD& md) { std::cout << "\n assigning modD"; if(&md == this) return *this; static_cast(*this) = md; if(md.pC != 0) pC = new C(*md.pC); else pC = 0; return *this; } ~modD() { std::cout << "\n destroying modD"; delete pC; // deleting a null pointer is safe } void say(const U& u) const { std::cout << "\n modD here"; if(pC) pC->say(); u.say(); } double& value() { if(pC == 0) pC = new C; return pC->value(); } private: C* pC; }; void main() { D d1; d1.value() = 3.1415927; U u; d1.say(u); D d2 = d1; d2.say(u); d1 = d2; modD md1; md1.value() = 3.1415927; md1.say(u); modD md2 = md1; md2.say(u); md1 = md2; md1.createC(3.1415927); modD md3 = md1; md1 = md3; }