////////////////////////////////////////////////////////////////// // DEM_AG2b.CPP -- demonstrates aggregation // // knows how to copy, assign, and destroy // // uses a more efficient copy ctor design // ////////////////////////////////////////////////////////////////// #include class base { public: base(void); base(const base& b); base(int x); virtual ~base(void); base& operator= (const base& b); friend ostream& operator<<(ostream& ostrm, const base& b); private: int data; }; class aggr { public: aggr(void); aggr(const aggr &a); aggr(int x1, int x2); virtual ~aggr(void); aggr& operator=(const aggr& a); friend ostream& operator<<(ostream& ostrm, const aggr& a); private: base b1; base b2; }; // //----< void constructor >------------------------------------- base::base(void) { cout << " base void constructor called\n"; } //----< copy constructor >------------------------------------- base::base(const base& b) : data(b.data) { cout << " base copy constructor called\n"; } //----< promotion constructor >-------------------------------- base::base(int x) : data(x) { cout << " base(int) constructor called\n"; cout << " set data = " << data << "\n"; } //----< destructor >------------------------------------------- base::~base(void) { cout << " base destructor called\n"; } //----< assignment >------------------------------------------- base& base::operator= (const base& b) { cout << " base operator= called\n"; data = b.data; return *this; } //----< insertion >-------------------------------------------- ostream& operator<<(ostream& ostrm, const base& b) { ostrm << b.data; return ostrm; } // //----< void constructor >------------------------------------- aggr::aggr(void) { cout << " aggr void constructor called\n"; } //----< copy constructor >------------------------------------- // note initialization - it's more efficient aggr::aggr(const aggr &a) : b1(a.b1), b2(a.b2) { cout << " aggr copy constructor called\n"; } //----< promotion constructor with initialization >------------ aggr::aggr(int size1, int size2) : b1(size1), b2(size2) { cout << " aggr(int,int) constructor called\n"; cout << " set b1 = " << b1 << endl; cout << " set b2 = " << b2 << endl; } //----< destructor >------------------------------------------- aggr::~aggr(void) { cout << " aggr destructor called\n"; } //----< assignment >------------------------------------------- aggr& aggr::operator=(const aggr &a) { cout << " aggr operator= called\n"; b1 = a.b1; b2 = a.b2; return *this; } //----< annunciator >------------------------------------------ void message(char *s) { cout << endl << s << " executable statement of main\n"; } void main() { //---------------------------------------------- message("1st"); base b1; message("2nd"); base b2 = b1; message("3rd"); b1 = b2; message("4th"); aggr a1; message("5th"); aggr a2(6,4); message("6th"); aggr a3 = a1; message("7th"); a3 = a2; message("no more"); } // // Look at 6th statement: // - in dem_agg2.cpp aggr copy ctor uses assignment in ctor body // which resulted in two operations for each data element, a // void construction and an assignment // - here in dem_ag2b.cpp the aggr copy ctor uses intialization // so only one operation occurs for each data element, a copy // construction // The moral of this story is that constructors should use init- // ialization whenever they can. The initializer calls a ctor, // thats the way it works. Which ctor is called is determined // by the syntax you use in the intializer.