C++ Unleashed Ebook free download pdf pdf

Gratis

0
0
945
3 months ago
Preview
Full text

1 H A P T E R Object-Oriented Analysis and Design

  The answer to both questions for the deposit issue is “no”: The customerdeposits money to either account in essentially the same way, and the outcome is pretty much the same; the ATM responds by incrementing the balance in the appropriateaccount. Object-Oriented Analysis and DesignHAPTER C 1 Establish Scenarios 1 O Now that we have a preliminary set of use cases and the tools with which to diagram the A B N JE relationship among the objects in the domain, we are ready to formalize the use cases A C D T E LY S -O and give them more depth.

3: Indicate amount and account 4: Check Balances, status, etc

9: Print Receipt

  Often, the timeline is dictated,top-down, by the client: “You have 18 months to get this done.” Ideally, you’ll examine the requirements and estimate the time it will take to design and implement the solution. That is the ideal; the practical reality is that most systems come with an imposed time limit and cost limit, and the real trick is to figure out how much of the required function-ality you can build in the allotted time—and at the allotted cost.

1.1. A

URING THE

TAGE OF

EVELOPM ENT

  Again, by creating classes for the interface to the device, you can plug in new devices with new protocols and not break any of the rest of your code; just create a new interfaceclass that supports the same interface (or a derived interface), and off you go. This model says that the body is not only an aggrega- tion of a head, two arms, and two legs, but that these objects (head, arms, legs) are Object-Oriented Analysis and DesignC HAPTER How might you design the classes required to reflect the various model lines of a typical car manufacturer?

1.19. Car

  It suggests that the class will delegate to the class allATM CheckingAccountresponsibility for managing the balance, while the will call on the CheckingAccount ATM to manage display to the user. In the early stages of the software development life cycle, it is important to note that the class diagram model attempts not only to definethe public interface for each class but to define the associations, aggregations, and generalizations defined between the individual classes.

2.1. A C++ R

  Because the data types used in a template class are not determined until the class is instantiated, you can write a generic Stackclass once; the items pushed on the stack and popped off the stack can vary from one instantiation of the class to another. Class diagrams represent template classes in the same way as normal classes, but they have a dotted rectangle in the upper-right corner that specifies the arguments to be usedin the class (see Figure 2.2).

ISTING EM PLATE LASS

C L

2.2. A C++ T

  The class diagram notation supports utility classes byprefacing the class name with Sine(), and Cosine(), : You simply use the functions contained in the class by fully qualifying the desired function name. There is no need to create an instance of this class because each function in the class is declaredstatic Utility Classes AssociationsAssociations represent a relationship between classes.

2.5. T Book C D

  Similarly, the Book class declares an instanceof the Person class with the name the_Person and provides the member functions Object-Oriented ProgrammingP ART I get_the_Person() and set_the_Person() to access the Person object. Note that thenamed association Reads is used only in the class diagram and is not defined in the C++ code other than as a comment.

2.6. T Renter C D

  ISTING HE LASS ECLARATION L #include “Apartment.h” class Renter{ public: Renter ();~Renter (); . .

2.7. T Apartment C D

  //## Association: Unnamed 2 //## Role: Apartment::Tenant C const Renter get_Tenant() const; I L M A void set_Tenant(const Renter value); P S S L E C D M + private: Renter Tenant; IG N IN }; G IN N:1 and 1:N Associations An N:1 or 1:N association—also referred to as a one-to-many relationship, exists when one object can exist for multiple instances of the another object, but the other object canexist only once for the original object. The class diagram notation for a one-to-many association is to place the name of the role of the association above theassociation line and to list the type of association below the line.

2.1. A M

  The Tenant to ApartmentBuilding association is represented in C++ in the same way as a 1:1 association: The Tenant class has a private attribute Lives_at that is of typeApartmentBuilding . (The class declaration in Listing 2.9 uses a template class oftype UnboundedSetByValue to hold all its residents.) Listing 2.8 shows the class declara- tion for the Tenant class.

2.8. T Tenant C D

  An C I L M A example of this type of association is the relationship between a contractor and a compa- P S S L E ny: A company can employ many contractors, and a contractor can simultaneously work C D M + E E + for many companies (see Figure 2.8). The C++ implementation of this association is similar to the apartment building example in the previous section: The maintains a private set of s namedCompany Contractor , and the maintains a set of s he works for namedEmployees Contractor Company .

2.11. T Company C D

  TransactionHistoryis represented in a class diagram by drawing a line between the two Containment classes with a solid diamond on the side of the class that contains the other class (see Figure 2.9). Balance TransactionHistory The Balance and TransactionHistory classes maintain a reference to theirBankAccount s, but are contained within the BankAccount class itself; the BankAccount class creates private instances of the Balance and TransactionHistory classes.

2.12. T BankAccount C D

  Generalization is represented in a class diagram by drawing an arrow from the specific class to the general class (see Figure 2.10). Implementing Class Design in C++HAPTER C 2 In C++, generalization is represented by suffixing the class declaration of the specific class with a colon followed by the name of the general class.

2.15. T Checking C D

  A collabo- C I L M A ration diagram allows you to visualize the arrangement of objects as they interact, but as P S S L E C the number of interactions increases, the more complex and unreadable the diagram D M + + E E becomes. After the design is complete, and the objects in an interaction diagram have been associ- ated with classes defined in class diagrams, the implementation in C++ is fairly straight-forward.

ATM: ATM

The collaboration

1. Check Balance

  The objects in these diagrams are listed here: The object is going to represent the ’s actions because theUserInterface Person Person never directly interacts with any of the other objects. The in Figures 2.12 and 2.13 hasPersonthree interactions with system objects: The UserInterface object must provide the Person object with the CheckBalance andWithdrawCash options, and must provide a way to give the Person cash dispensed fromthe CheckingAccount .

2.18. T UserInterface C D

  In this example, theATMclass receives the and messages, the CheckBalance DisplayBalance CheckingAccountclass receives the and messages, and the class GetBalance WithdrawCash Receipt receives the message. Print Listing 2.19 shows the public interface for the class, Listing 2.20 shows the publicATMinterface for the class, and Listing 2.21 shows the public interface for CheckingAccount the class.

2.21. T P

  I Receipt Cclass Receipt{ public: BOOL Print ();};Now that the public interface has been extracted from the interaction diagrams and entered into the class declarations, the next step is to implement the visibility of the indi-vidual classes. CheckingAccountThere is no correct implementation decision here; it depends on the other interaction dia- grams and other design constraints such as the storage mechanism for the (for example, the s may be stored in a database andCheckingAccount CheckingAccount only one instance may be visible and available inside the object).

ISTING HE LASS ECLARATION WITH THE ONTAINED BJECT

  private:// Private AttributesATM the_ATM; };Next, the object interacts with only the object and, as mentioned ATM CheckingAccount in the previous discussion, will contain an instance of the object. CheckingAccountBecause it contains the object, it is responsible for communicating CheckingAccountwith the on behalf of the .

2.23. T ATM C D C CheckingAccount

  The easy way to accomplish this is to follow the arrows in Implementing Class Design in C++HAPTER C 2 The first message sent, CheckBalance , is from the UserInterface object to the ATM object. T char * CheckingAccount::GetBalance(){ // Look up the Balance from the database// Call ATM::DisplayBalance() to fire the next message// GetParent() returns a pointer to our parent ATM classGetParent()->DisplayBalance ();// Return the balance to the caller return szBalance; }The UserInterface::WithdrawCash() function is derived in a similar manner, and its implementation is displayed in Listing 2.26.

2.26. T UserInterface::WithdrawCash() F

  The assumption made in this listing is that is a GetParent()function that exists in each class and that it returns a pointer to its parent. Furthermore, the assumption is made that there is a function, , that exists in the GetReceipt()object that returns the system object.

ISTING HE UNCTION

  Not Logged In CancelableGetting Account Info Canceled Getting Password Logged In Object-Oriented ProgrammingP ART I What this diagram translates to in programming terms is that the object (or, in the case of C++, the class) must provide an interface to allow a user to log in. More specifically, the class must somehow prompt the user for his or her account information( GettingAccountInfo() ), prompt for his or her password ( GettingPassword() ), and change the state of the object from NotLoggedIn to LoggedIn —all the while allowing theuser to cancel the operation at any point ( Cancelable ).

2.28. T CustomerAccount C D

  LogOut() m_fLoggedIn falseThe function performs the actions specified in the state transition diagram: It LogIn first prompts the customer for an account number and stores it in .szAccountNumber Implementing Class Design in C++HAPTER C 2 A real-world implementation of this object would involve more sophisticated cancella- tion methodologies, but to impress on you the notion that this action can be canceled, the account number is compared to Cancel before continuing. If the customer has entered both an account number and a password, the values are compared by anotherfunction ValidPassword() that probably does some database lookups and comparisons.

2.29. T CustomerAccount C

  The implementation of activity diagrams is very similar to the implementation of state transition diagrams: The state represents the beginning of an operation, and the Startstate represents the conclusion. In this example, the procedure being mod-eled is a cash withdrawal transaction; the actual implementation of the object operations are superfluous to the implementation of the cash withdrawal transaction procedure.

2.30. T Customer C D

  FundsAvailable(); Object-Oriented ProgrammingP ART I Summary This chapter has discussed the implementation of some of the more popular UML design models in C++. In some cases, the realization of these designs intoC++ code is systematic; in other cases, it will be application dependent—but in any case, a solid foundation of the techniques used to realize these designs is imperative to the suc-cess of the project.

3 Inheritance, Polymorphism, and Code Reuse

  If the new object is the first object inserted, it is by definition the smallest object in the list, but any object arriving at the tail must be the smallest, or it would already have beeninserted by another node, higher up in the list. The Dataobject is passed along to the next node in the list:case kIsSmaller: nextNode = nextNode->Insert(theData);return this; In this case, the InternalNode does just what the TailNode did: It creates a newInternalNode and tells the new InternalNode to point to it (that is, the newInternalNode points to the InternalNode that created it).

ISTING BJECT RIENTED

INKED

3.1. O -O L L

  Every node other thanthe TailNode knows only that it has a pointer to the next node in the list; it does not know whether that node is an InternalNode or a TailNode , but the static type makes allthe difference. That is, the LinkedList tells the next node to show itself, each InternalNode shows its data and then passes the command along to its next node; the TailNode acts as the sen-try, stopping the chain.

3.2. D C A D T

  ISTING ATA LASS AS AN BSTRACT ATA YPE L class Data{ public: Data(int val):myVal(val){} virtual ~Data(){}int Compare(const Data &); virtual void Show() = 0;protected: int myVal;}; Object-Oriented ProgrammingP ART I The semantics of this declaration are that Data is an ADT, and that to create a concrete Data class, you must override the Show() method and provide a non-pure virtual (impurevirtual?) method. The important idea is that the designer of Data is requiring derived classes to override the Show() method, and to provide a concrete implementation.

3.3. C D T

  ISTING ONCRETE ATA YPES L class IntegerData : public Data{ public: IntegerData(int val) : Data(val) {} virtual ~IntegerData() {}virtual void Show(); private: }; class GraphicData : public Data{ public: GraphicData(int val) : Data(val) {} virtual ~GraphicData() {}virtual void Show(); private: };Each of these classes overrides the method. The calling code need not know which method will be called; Show()by the power of polymorphism, the correct method is invoked, as demonstrated by Listing 3.4.

3.4. P D T

  Any questions?\n”; C E IS E U M , } S , E Even though the Data class provides an implementation of Show() , the method is still pure virtual, and the class is still abstract. Remember that the s do not know what kind of data object they’re Data Nodedealing with; they just delete the object as part of their own destructor: ~InternalNode(){ delete nextNode; delete myData; }Note that is declared in the class as follows:myData InternalNode Data * myData;If the object’s destructor is not virtual, then the part of the is Data Data IntegerDatadeleted, but the remainder of the derived object is not.

ISTING EM BER

VERLOADING O L

3.5. M

  GetHeight() << endl; N H R C E return 0; IS E U M , } S , E As you can see, a class consists of a pair of points, each of which marks anRectangleopposite corner of the rectangle. It is a trivial matter Rectangleto overload the constructor so that you can create a not by passing in a pair of Rectanglepoints, but by passing in the x and y coordinates of the upper-left and lower-right corners of the rectangle, as shown in Listing 3.6.

3.6. O C

  GetHeight() << endl; return 0; Inheritance, Polymorphism, and Code ReuseHAPTER C 3 It is important to note that the default constructor is not the constructor provided by default, but rather is any constructor that takes no parameters. There are three other methods that the compiler provides for you if you don’t declare one: the destructor, the copy constructor, and the assignment operator.

3.7. M H

  Also, although I normally set pointers to after deleting them, I don’t do so NULL Object-Oriented ProgrammingP ART I in the destructor because there is no chance of the pointer being used again (the object is about to wink out of existence). If the object is a user-defined object (such as aRectangle object from the example in the last discussion), that class’s copy constructor is called to create the temporary object.

3.8. E S C C

  We then reportmyRect Inheritance, Polymorphism, and Code ReuseHAPTER C 3 the address of the rectangle itself, followed by the address of the object held by myUpperLeft and then the address of that pointer. The critical thing to note is that the address of the myUpperLeft Point member of r (the rectangle inSomeFunction() ) is the same as the address of the myUpperLeft Point member of myRect .

3.9. D C

  Suppose that you write the following statement:myRect = otherRect; You know that the compiler turns this code into the following:myRect.operator=(otherRect);That is, the compiler turns the assignment into a method call on the object on the left side of the assignment operator, and passes in the object on the right side as a parameter. It has a bug in it; see whether you can find it before reading the analysis:Rectangle & Rectangle::operator=(const Rectangle & rhs){ delete myUpperLeft;delete myLowerRight; myUpperLeft = new Point(*rhs.myUpperLeft);myLowerRight= new Point(*rhs.myLowerRight); return *this; }Note that this assignment operator carefully deletes the original member variables before creating new values, avoiding the obvious potential for a memory leak.

3.10. C

HECK FOR

SSIGNM ENT TO

  We can, of course, assign any meaning we want—we’re free to use the increment operator toreturn the position of the upper-left corner’s coordinates:Point upperLeft = myRect++; // return the current upper left via➥ operator++ ’s value to 1 greater. To support this, the increment operator must be prepared to return the value that was originally inb Overloading the Increment Operators ( 6.

3.11. I

NCREM ENT

  Although C++ does not sup- H R C E IS E U M port the idea of virtual constructors, you often need to be able to return a copy of an , S , E object that is an exact duplicate, even when treating the object polymorphically. When you ask for the member variable, the compiler does not necessarilyageknow which object’s age you mean and will issue an error along these lines:‘Griffin::GetAge’ is ambiguous, could be the ‘GetAge’ in base ‘Animal’ of base ‘Lion’of class ‘Griffin’ or the ‘GetAge’ in base ‘Animal’ of base‘Eagle’ of class ‘Griffin’.

3.14. V

  The problem with this solution is that both Lion and Eagle must know that they may be involved in a multiple inheritance relationship; the virtualkeyword must be on their declaration of inheritance, not that of Griffin . This is very unusual, but it is the only way to resolve the ambiguity of Lion initializing to one value and Eagle initializing to another.

ISTING NITIALIZING ASE LASSES WITH

3.15. I B C

  Inheritance, Polymorphism, and Code ReuseC HAPTER 3 3 I N H E R IT A N C E , P O LY M O R P H IS M , A N D C O D E R E U S E Implementation ART IssuesP II I N T HIS P ART M emory M anagement N HIS HAPTER I T C 4 • M emory M anagementand Pointers 127 R E T P A H Implementation IssuesP ART II In my experience of teaching C++ to literally more than 10,000 students, both in person and online, I’ve found that the single hardest conceptual area is memory management. Refer again to this statement:ref = y; This statement did not point ref to y —instead, it was exactly as if I had written this: Memory ManagementHAPTER C 4 x = y;Thus, here is the correct answer:x = 10, y = 10, ref = 10Finally, pointers and references present a specific and difficult challenge in the face of exceptions.

4.1. A M S

  If you make this mistake in a function that allocates a lot of memory (a few big objects or lots of small objects), and you call this function repeatedly, it is entirely possible tocrash your program (or slow it down tremendously) because you will run out of available memory. If you forget to use the delete[] operator and instead call delete (with nobrackets), you will deallocate only the first object, and the rest of the memory will be lost.

4.3. U delete[]

  GetValue() << endl; delete [] pArray; }Here is the output from the preceding listing:In main, ready to call someFunction…In myClass constructorIn myClass constructorIn myClass constructorIn myClass constructorIn myClass constructor pArray[0]: 0pArray[1]: 1 pArray[2]: 2pArray[3]: 3 pArray[4]: 4In myClass DestructorIn myClass DestructorIn myClass DestructorIn myClass DestructorIn myClass Destructor In main, returned from someFunction. This call causes each of the objects to be destroyed in turn:delete [] pArrayFor efficiency, the delete operator (without square braces) assumes that you want to delete only a single object.

4.4. D

  If you are going to fail, you want to fail with a bang, not a whimper—that is, you want to failpredictably (so that you can find the bug) and you want to fail where the bug is, not later in the program. The value beingpThreepointed to can’t be changed, and can’t be changed to point to anything else:pThree const int * const pThree; // constant pointer to a constant integer The trick to keeping this straight is to look to the right of the keyword to find outconstwhat is being declared constant.

4.5. R R T O

  }The output is as follows:In myClass constructor rC’s value: 5In myClass DestructorIn this example, you create a pointer to the memory on the heap (by taking the address of the reference) and then you delete that object. A M Typically, the value in the block is passed using references, and the function that created N E A M G the memory is the one that deletes it.

4.6. H

BJECTS AND

  Because the exception is thrown,the statements are never reached, and we have created a memory leak.delete Notice that in both rounds, the ’s destructor is called. Notedelete catchthat we have to pull the pointers out of the scope of the block so that can seetry catch them, as shown in Listing 4.7.

4.7. D P catch B

  Copying the sdeleteinto all the blocks is not a good long-term solution; it makes for code that is hardcatchto maintain and prone to error. An object of this class isauto_ptrintended to act like a pointer but to sit on the stack so that it is destroyed when an excep- tion is thrown.

4.8. U auto_ptr

  The manages the memorymain() catch auto_ptr for you; you just pass in a pointer to the object and the does the rest.auto_ptr Note that there is a subtle bug in this program; I will discuss it in a moment. The first approach is to invoke the copy constructor:Point * ptrOne = ptrTwo; The second way to copy a pointer is to call the assignment operator:Point * ptrOne; ptrOne = ptrTwo; Implementation IssuesP ART II In either case, the author of the auto_ptr template class has three choices: ship when a pointer is assigned.

Dokumen baru