Here is hw 3. The deadline for hw 2 has been extended to Oct. 12. -- Karl Lieberherr -------------------------------------------------------------------------- Object-oriented Systems Fall 1995 COM 3360/NTU SE737 --------------------------------------------------------------------------- Assignment 3 Due date: Monday, Oct. 23 NTU: one week later --------------------------------------------------------------------------- This assignment is stored in file $OO/hw/3 in file assign.txt ========= On CCS Northeastern machines, OO=/course/com3360 On the WWW, OO = http://www.ccs.neu.edu/research/demeter/course ========= Use the following header for your written homework submissions and put it at the top of the first page: Course number: COM 3360/NTU SE737 (whichever applies) Name: Account name: Assignment number: Date: Send your solution by email to the teaching assistant (kate) with subject line: Subject: COM 3360/NTU SE737 HW number where number is the homework number. ========== Put the solutions to this homework into directory /proj/adaptive3/projects/com3360-f95/YOUR_LOGIN/hw3 ========== Midterm time is approaching. For COM3360 students, it will be held on Oct. 30. Sample midterm exams are in $OO/exams/m-3360* In $OO/exams/practice-exam-handout you find instructions on how to prepare your own practice exams. --------- When you have questions about concepts and tools, please check first URL: ftp://ftp.ccs.neu.edu/pub/people/lieber/faq/Demeter-FAQ for an answer. Whenever you have questions about course material, please send e-mail to: mail lieberherr@ccs.neu.edu ccs.courses.com3360@ccs.neu.edu =============================================================== Theme: Writing a complete C++ program which traverses objects to perform a simple addition task. Develop your own class dictionary Maintaining object-oriented programs (Effect of the Law of Demeter) =============================================================== PART A: ======= Do Assignment 3 page 551 in the Demeter book. Here is more information for PART A/Part 3 which helps you with the solution of the Conglomerate example which is described on page 553. TYPO in book: In 3rd and 4th line from top of page 552: The Trip class dictionary is in Fig. 4.12 page 94 (not in Fig. 4.8 page 91). The class dictionary is repeated here for your convenience (ignore all the strings of the form "..."): (Chapter 1 in the Demeter book contains much of the solution for PART A.) Conglomerate = "Conglomerate" ":" DemIdent "Head Office" ":" Company . Subsidiary : WholyOwned | PartiallyOwned *common* Company . WholyOwned = "Wholy" "owned" . PartiallyOwned = "Partially" "owned" "stake" "=" DemNumber . Company = DemString "Registered" "Office" Address "Turnover" ":" DemString "Officers" ":" Officer_List [ "Subsidiaries" "{" Subsidiary_List "}" ] . Address = "Street" "-" DemString "City" "-" DemString "State" "-" DemIdent "Country" "-" DemIdent "." . Officer : Shareholding_Officer | Ordinary_Officer *common* "Name" "-" DemString "Title" "-" DemString "Salary" "-" <salary >Salary "." . Salary = <v > DemNumber . Shareholding_Officer = "Shareholder" <share_percentage > DemNumber "percent control" . Ordinary_Officer = "Ordinary" . Officer_List : Officer_Empty | Officer_NonEmpty . Subsidiary_List : Subsidiary_Empty | Subsidiary_NonEmpty . Officer_Empty = . Officer_NonEmpty = <first >Officer <rest >Officer_List . Subsidiary_Empty = . Subsidiary_NonEmpty = <first >Subsidiary <rest >Subsidiary_List . The C++ constructor calls for testing are repeated here for your convenience: DemIdent* iIdent1 = new DemIdent( "TransGlobal" ); DemString* iString2 = new DemString( "TransGlobal Illumination" ); DemString* iString3 = new DemString( "23 Rue du Lac" ); DemString* iString4 = new DemString( "Geneva" ); DemIdent* iIdent5 = new DemIdent( "GE" ); DemIdent* iIdent6 = new DemIdent( "Switzerland" ); Address* iAddress7 = new Address( iString3,iString4,iIdent5,iIdent6 ); DemString* iString8 = new DemString( "4bn" ); DemNumber* iNumber9 = new DemNumber( 60 ); Shareholding_Officer* iShareholding_Officer10 = new Shareholding_Officer( iNumber9 ); DemString* iString11 = new DemString( "George Bush" ); iShareholding_Officer10->set_data_member( 1,iString11 ); DemString* iString12 = new DemString( "Chief Executive Officer and President" ); iShareholding_Officer10->set_data_member( 2,iString12 ); DemNumber* iNumber13 = new DemNumber( 200000 ); Salary* iSalary14 = new Salary( iNumber13 ); iShareholding_Officer10->set_data_member( 3,iSalary14 ); DemNumber* iNumber15 = new DemNumber( 30 ); Shareholding_Officer* iShareholding_Officer16 = new Shareholding_Officer( iNumber15 ); DemString* iString17 = new DemString( "Hans Kohl" ); iShareholding_Officer16->set_data_member( 1,iString17 ); DemString* iString18 = new DemString( "Chief Financial Officer" ); iShareholding_Officer16->set_data_member( 2,iString18 ); DemNumber* iNumber19 = new DemNumber( 150000 ); Salary* iSalary20 = new Salary( iNumber19 ); iShareholding_Officer16->set_data_member( 3,iSalary20 ); Ordinary_Officer* iOrdinary_Officer21 = new Ordinary_Officer( ); DemString* iString22 = new DemString( "Michael Gorbachev" ); iOrdinary_Officer21->set_data_member( 0,iString22 ); DemString* iString23 = new DemString( "Secretary" ); iOrdinary_Officer21->set_data_member( 1,iString23 ); DemNumber* iNumber24 = new DemNumber( 100000 ); Salary* iSalary25 = new Salary( iNumber24 ); iOrdinary_Officer21->set_data_member( 2,iSalary25 ); Officer_Empty* iOfficer_Empty26 = new Officer_Empty( ); Officer_NonEmpty* iOfficer_NonEmpty27 = new Officer_NonEmpty( iOrdinary_Officer21,iOfficer_Empty26 ); Officer_NonEmpty* iOfficer_NonEmpty28 = new Officer_NonEmpty( iShareholding_Officer16,iOfficer_NonEmpty27 ); Officer_NonEmpty* iOfficer_NonEmpty29 = new Officer_NonEmpty( iShareholding_Officer10,iOfficer_NonEmpty28 ); WholyOwned* iWholyOwned30 = new WholyOwned( ); DemString* iString31 = new DemString( "TransGlobal Glasnost" ); DemString* iString32 = new DemString( "12 Borisinsky Way" ); DemString* iString33 = new DemString( "Moscow" ); DemIdent* iIdent34 = new DemIdent( "Russia" ); DemIdent* iIdent35 = new DemIdent( "USSR" ); Address* iAddress36 = new Address( iString32,iString33,iIdent34,iIdent35 ); DemString* iString37 = new DemString( "2bn" ); DemNumber* iNumber38 = new DemNumber( 80 ); Shareholding_Officer* iShareholding_Officer39 = new Shareholding_Officer( iNumber38 ); DemString* iString40 = new DemString( "Boris Yeltsin" ); iShareholding_Officer39->set_data_member( 1,iString40 ); DemString* iString41 = new DemString( "Chief Executive Officer" ); iShareholding_Officer39->set_data_member( 2,iString41 ); DemNumber* iNumber42 = new DemNumber( 200000 ); Salary* iSalary43 = new Salary( iNumber42 ); iShareholding_Officer39->set_data_member( 3,iSalary43 ); DemNumber* iNumber44 = new DemNumber( 5 ); Shareholding_Officer* iShareholding_Officer45 = new Shareholding_Officer( iNumber44 ); DemString* iString46 = new DemString( "Eduard Shevardnadze" ); iShareholding_Officer45->set_data_member( 1,iString46 ); DemString* iString47 = new DemString( "Chief Financial Officer" ); iShareholding_Officer45->set_data_member( 2,iString47 ); DemNumber* iNumber48 = new DemNumber( 150000 ); Salary* iSalary49 = new Salary( iNumber48 ); iShareholding_Officer45->set_data_member( 3,iSalary49 ); DemNumber* iNumber50 = new DemNumber( 5 ); Shareholding_Officer* iShareholding_Officer51 = new Shareholding_Officer( iNumber50 ); DemString* iString52 = new DemString( "Ivan Silayev" ); iShareholding_Officer51->set_data_member( 1,iString52 ); DemString* iString53 = new DemString( "President" ); iShareholding_Officer51->set_data_member( 2,iString53 ); DemNumber* iNumber54 = new DemNumber( 150000 ); Salary* iSalary55 = new Salary( iNumber54 ); iShareholding_Officer51->set_data_member( 3,iSalary55 ); Ordinary_Officer* iOrdinary_Officer56 = new Ordinary_Officer( ); DemString* iString57 = new DemString( "Georg Publiksky" ); iOrdinary_Officer56->set_data_member( 0,iString57 ); DemString* iString58 = new DemString( "Secretary" ); iOrdinary_Officer56->set_data_member( 1,iString58 ); DemNumber* iNumber59 = new DemNumber( 100000 ); Salary* iSalary60 = new Salary( iNumber59 ); iOrdinary_Officer56->set_data_member( 2,iSalary60 ); Officer_Empty* iOfficer_Empty61 = new Officer_Empty( ); Officer_NonEmpty* iOfficer_NonEmpty62 = new Officer_NonEmpty( iOrdinary_Officer56,iOfficer_Empty61 ); Officer_NonEmpty* iOfficer_NonEmpty63 = new Officer_NonEmpty( iShareholding_Officer51,iOfficer_NonEmpty62 ); Officer_NonEmpty* iOfficer_NonEmpty64 = new Officer_NonEmpty( iShareholding_Officer45,iOfficer_NonEmpty63 ); Officer_NonEmpty* iOfficer_NonEmpty65 = new Officer_NonEmpty( iShareholding_Officer39,iOfficer_NonEmpty64 ); Company* iCompany66 = new Company( iString31,iAddress36,iString37,iOfficer_NonEmpty65,NULL ); iWholyOwned30->set_data_member( 0,iCompany66 ); Subsidiary_Empty* iSubsidiary_Empty67 = new Subsidiary_Empty( ); Subsidiary_NonEmpty* iSubsidiary_NonEmpty68 = new Subsidiary_NonEmpty( iWholyOwned30,iSubsidiary_Empty67 ); Company* iCompany69 = new Company( iString2,iAddress7,iString8,iOfficer_NonEmpty29,iSubsidiary_NonEmpty68 ); Conglomerate* iConglomerate70 = new Conglomerate( iIdent1,iCompany69 ); Explanation of set_data_member: The function set_data_member(i,object) takes two arguments. The first is an index which selects a data member and the second argument contains the object which needs to be put into the data member. This function is used to set inherited data members. An easy solution is to reimplement set_data_member(i, object) by a function set_NAME(object), where NAME is the name of some data member. E.g., function set_title(object) would allow you to set the title part to a new object. To implement a constructor for DemString, you might want to use: DemString::DemString( char* val_in ) { if( val_in ) { this->val = new char[strlen( val_in ) + 1]; strcpy( this->val,val_in ); } else this->val = NULL; } This definition is also used in the Demeter System. The above object of class Conglomerate is described below in the object-graph notation: : Conglomerate ( < name > : DemIdent "TransGlobal" < head > : Company ( < name > : DemString "TransGlobal Illumination" < location > : Address ( < street > : DemString "23 Rue du Lac" < city > : DemString "Geneva" < state > : DemIdent "GE" < country > : DemIdent "Switzerland" ) < turnover > : DemString "4bn" < officers > : Officer_NonEmpty ( < first > : Shareholding_Officer ( < share_percentage > : DemNumber "60" < name > : DemString "George Bush" < title > : DemString "Chief Executive Officer and President" < salary > : Salary ( < v > : DemNumber "200000" ) ) < rest > : Officer_NonEmpty ( < first > : Shareholding_Officer ( < share_percentage > : DemNumber "30" < name > : DemString "Hans Kohl" < title > : DemString "Chief Financial Officer" < salary > : Salary ( < v > : DemNumber "150000" ) ) < rest > : Officer_NonEmpty ( < first > : Ordinary_Officer ( < name > : DemString "Michael Gorbachev" < title > : DemString "Secretary" < salary > : Salary ( < v > : DemNumber "100000" ) ) < rest > : Officer_Empty ( ) ) ) ) < subsideries > : Subsidiary_NonEmpty ( < first > : WholyOwned ( < company > : Company ( < name > : DemString "TransGlobal Glasnost" < location > : Address ( < street > : DemString "12 Borisinsky Way" < city > : DemString "Moscow" < state > : DemIdent "Russia" < country > : DemIdent "USSR" ) < turnover > : DemString "2bn" < officers > : Officer_NonEmpty ( < first > : Shareholding_Officer ( < share_percentage > : DemNumber "80" < name > : DemString "Boris Yeltsin" < title > : DemString "Chief Executive Officer" < salary > : Salary ( < v > : DemNumber "200000" ) ) < rest > : Officer_NonEmpty ( < first > : Shareholding_Officer ( < share_percentage > : DemNumber "5" < name > : DemString "Eduard Shevardnadze" < title > : DemString "Chief Financial Officer" < salary > : Salary ( < v > : DemNumber "150000" ) ) < rest > : Officer_NonEmpty ( < first > : Shareholding_Officer ( < share_percentage > : DemNumber "5" < name > : DemString "Ivan Silayev" < title > : DemString "President" < salary > : Salary ( < v > : DemNumber "150000" ) ) < rest > : Officer_NonEmpty ( < first > : Ordinary_Officer ( < name > : DemString "Georg Publiksky" < title > : DemString "Secretary" < salary > : Salary ( < v > : DemNumber "100000" ) ) < rest > : Officer_Empty ( ) ) ) ) ) ) ) < rest > : Subsidiary_Empty ( ) ) ) ) Here is yet another description of the same object in an English-like notation: Conglomerate : TransGlobal Head Office : "TransGlobal Illumination" Registered Office Street - "23 Rue du Lac" City - "Geneva" State - GE Country - Switzerland. Turnover : "4bn" Officers : Shareholder 60 percent control Name - "George Bush" Title - "Chief Executive Officer and President" Salary - 200000. Shareholder 30 percent control Name - "Hans Kohl" Title - "Chief Financial Officer" Salary - 150000. Ordinary Name - "Michael Gorbachev" Title - "Secretary" Salary - 100000. Subsidiaries { Wholy owned "TransGlobal Glasnost" Registered Office Street - "12 Borisinsky Way" City - "Moscow" State - Russia Country - USSR. Turnover : "2bn" Officers : Shareholder 80 percent control Name - "Boris Yeltsin" Title - "Chief Executive Officer" Salary - 200000. Shareholder 5 percent control Name - "Eduard Shevardnadze" Title - "Chief Financial Officer" Salary - 150000. Shareholder 5 percent control Name - "Ivan Silayev" Title - "President" Salary - 150000. Ordinary Name - "Georg Publiksky" Title - "Secretary" Salary - 100000. } Your program should enter and exit the various objects as shown in the following trace: In Conglomerate::add_salary In Company::add_salary In Officer_NonEmpty::add_salary In Shareholding_Officer::add_salary In Officer::add_salary In Salary::add_salary Out Salary::add_salary Out Officer::add_salary Out Shareholding_Officer::add_salary In Officer_NonEmpty::add_salary In Shareholding_Officer::add_salary In Officer::add_salary In Salary::add_salary Out Salary::add_salary Out Officer::add_salary Out Shareholding_Officer::add_salary In Officer_NonEmpty::add_salary In Ordinary_Officer::add_salary In Officer::add_salary In Salary::add_salary Out Salary::add_salary Out Officer::add_salary Out Ordinary_Officer::add_salary In Officer_List::add_salary Out Officer_List::add_salary Out Officer_NonEmpty::add_salary Out Officer_NonEmpty::add_salary Out Officer_NonEmpty::add_salary In Subsidiary_NonEmpty::add_salary In WholyOwned::add_salary In Subsidiary::add_salary In Company::add_salary In Officer_NonEmpty::add_salary In Shareholding_Officer::add_salary In Officer::add_salary In Salary::add_salary Out Salary::add_salary Out Officer::add_salary Out Shareholding_Officer::add_salary In Officer_NonEmpty::add_salary In Shareholding_Officer::add_salary In Officer::add_salary In Salary::add_salary Out Salary::add_salary Out Officer::add_salary Out Shareholding_Officer::add_salary In Officer_NonEmpty::add_salary In Shareholding_Officer::add_salary In Officer::add_salary In Salary::add_salary Out Salary::add_salary Out Officer::add_salary Out Shareholding_Officer::add_salary In Officer_NonEmpty::add_salary In Ordinary_Officer::add_salary In Officer::add_salary In Salary::add_salary Out Salary::add_salary Out Officer::add_salary Out Ordinary_Officer::add_salary In Officer_List::add_salary Out Officer_List::add_salary Out Officer_NonEmpty::add_salary Out Officer_NonEmpty::add_salary Out Officer_NonEmpty::add_salary Out Officer_NonEmpty::add_salary Out Company::add_salary Out Subsidiary::add_salary Out WholyOwned::add_salary In Subsidiary_List::add_salary Out Subsidiary_List::add_salary Out Subsidiary_NonEmpty::add_salary Out Company::add_salary Out Conglomerate::add_salary And your program should produce as output: TOTAL SALARY = 1050000 PART B: ======= This is a question about program maintenance. Consider the two collections of functions shown below: all_e and all_e2. all_e consists of three functions which violate the Law of Demeter (LoD). and all_e2 consists of 5 functions. Which collection of functions is easier to maintain? all_e or all_e2? The one satisfying the LoD should be easier to maintain. Find out yourself. Change class B from B = <e> E. to B = <x> X. X = <e> E. Into which of the two collections of functions is it easier to incorporate the change? all_e or all_e2? How many classes do you have to update in each case? The set of functions satisfying the Law should do so also after maintanance. //////////////////////////////////////////////////////////////// all_e // Violates the LoD #include "UNKNOWN.h" // 3 function solution // A = <b > B // <c > C // <d > D . void A::all_e( ) { DEM_TRACE("A","void A::all_e()"); // prefix class wrappers cout << this -> get_b() -> get_e(); // violation LoD // outgoing calls this->get_c()->all_e( ); this->get_d()->all_e( ); } // C = <b > B . void C::all_e( ) { DEM_TRACE("C","void C::all_e()"); // prefix class wrappers cout << this -> get_b() -> get_e(); //violation LoD } // D = <b > B . void D::all_e( ) { DEM_TRACE("D","void D::all_e()"); // prefix class wrappers cout << this -> get_b() -> get_e(); //violation LoD } //////////////////////////////////////////////////////////////////// all_e2 // 5 function solution // A = <b > B // <c > C // <d > D . void A::all_e2( ) { DEM_TRACE("A","void A::all_e2()"); // outgoing calls this->get_b()->all_e2( ); this->get_c()->all_e2( ); this->get_d()->all_e2( ); } // C = <b > B . void C::all_e2( ) { DEM_TRACE("C","void C::all_e2()"); // outgoing calls this->get_b()->all_e2( ); } // D = <b > B . void D::all_e2( ) { DEM_TRACE("D","void D::all_e2()"); // outgoing calls this->get_b()->all_e2( ); } // B = <e > E . void B::all_e2( ) { DEM_TRACE("B","void B::all_e2()"); // outgoing calls this->get_e()->all_e2( ); } // E = "e" . void E::all_e2( ) { DEM_TRACE("E","void E::all_e2()"); // prefix class wrappers cout << this; } Update file which-is-better.C in $OO/hw/3/law/after-maintenance and compile and run the program (use demeter). After copying $OO/hw/3/law/after-maintenance and running demeter, you will get compilation errors. This is intended since you need to first bring the member functions in which-is-better.C in synchrony with the class structure in cd.cd. In other words, you have to do the maintenance work first. What to turn in: Your modified file which-is-better.C with your changed lines for the new class structure marked with //<=== at the end of the line.