1. Trang chủ
  2. » Công Nghệ Thông Tin

C++ Primer Plus (P44) docx

20 348 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 20
Dung lượng 182,79 KB

Nội dung

1:Start with the following class declaration: // base class class Cd { // represents a CD disk private: char performers[50]; char label[20]; int selections; // number of selections double playtime; // playing time in minutes public: Cd(char * s1, char * s2, int n, double x); Cd(const Cd & d); Cd(); ~Cd(); void Report() const; // reports all CD data Cd & operator=(const Cd & d); }; Derive a Classic class that adds an array of char members that will hold a string identifying the primary work on the CD. If the base class requires that any functions be virtual, modify the base class declaration to make it so. If a declared method is not needed, remove it from the definition. Test your product with the following program: #include <iostream> using namespace std; #include "classic.h" // which will contain #include cd.h void Bravo(const Cd & disk); int main() { Cd c1("Beatles", "Capitol", 14, 35.5); Classic c2 = Classic("Piano Sonata in B flat, Fantasia in C", "Alfred Brendel", "Philips", 2, 57.17); Cd *pcd = &c1; cout << "Using object directly:\n"; This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. c1.Report(); // use Cd method c2.Report(); // use Classic method cout << "Using type cd * pointer to objects:\n"; pcd->Report(); // use Cd method for cd object pcd = &c2; pcd->Report(); // use Classic method for classic object cout << "Calling a function with a Cd reference argument:\n"; Bravo(c1); Bravo(c2); cout << "Testing assignment: "; Classic copy; copy = c2; copy.Report() return 0; } void Bravo(const Cd & disk) { disk.Report(); } 2:Repeat exercise 1, but this time use dynamic memory allocation instead of fixed-size arrays for the various strings tracked by the two classes. 3:Revise the baseDMA-lacksDMA-hasDMA class hierarchy so that all three classes are derived from an abstract base class. Test the result with a program similar to the one in Listing 13.10. That is, it should feature an array of pointers to the abstract base class and allow the user to make runtime decisions as to what types of objects are created. 4:The Benevolent Order of Programmers maintains a collection of bottled port. To describe it, the BOP Portmaster has devised a Port class as declared below: #include <iostream> using namespace std; class Port This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. { private: char * brand; char style[20]; // i.e., tawny, ruby, vintage int bottles; public: Port(const char * br = "none", const char * st = "none", int b = 0); Port(const Port & p); // copy constructor virtual ~Port() { delete [] brand; } Port & operator=(const Port & p); Port & operator+=(int b); // adds b to bottles Port & operator-=(int b); // subtracts b from bottles, if //available int BottleCount() const { return bottles; } virtual void Show() const; friend ostream & operator<<(ostream & os, const Port & p); }; The Show() method presents information in the following format: Brand: Gallo Kind: tawny Bottles: 20 The operator<<() function presents information in the following format (no newline at the end): Gallo, tawny, 20 The Portmaster completed the method definitions for the Port class and then derived the VintagePort class as follows before being relieved of his position for accidentally routing a bottle of '45 Cockburn to someone preparing an experimental barbecue sauce. class VintagePort : public Port // style necessarily = "vintage" { This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. private: char * nickname; // i.e., "The Noble" or "Old Velvet", etc. int year; // vintage year public: VintagePort(); VintagePort(const char * br, int b, const char * nn, int y); VintagePort(const VintagePort & vp); ~VintagePort() { delete [] nickname; } VintagePort & operator=(const VintagePort & vp); void Show() const; friend ostream & operator<<(ostream & os, const VintagePort & vp); }; You get the job of completing the VintagePort work. Your first task is to re-create the Port method definitions, for the former Portmaster immolated his upon being relieved. a. Your second task is to explain why certain methods are redefined and others are not. b. Your third task is to explain why operator=() and operator<<() are not virtual. c. Your fourth task is to provide definitions for the VintagePort methods. d. CONTENTS This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. CONTENTS Chapter 14. REUSING CODE IN C++ You will learn about the following in this chapter: Classes with Object Members Private Inheritance Multiple Inheritance Class Templates Summary Review Questions Programming Exercises One of the main goals of C++ is to facilitate the reuse of code. Public inheritance is one mechanism for achieving this goal, but not the only one. This chapter will investigate other choices. One technique is using class members that are themselves objects of another class. This is referred to as containment or composition or layering. Another option is using private or protected inheritance. Containment, private inheritance, and protected inheritance typically are used to implement has-a relationships, that is, relationships for which the new class has an object of another class. For example, a Stereo class might have a CdPlayer object. Multiple inheritance lets you create classes that inherit from two or more base classes, combining their functionality. Chapter 10, "Objects and Classes," introduced function templates. Now we'll look at class templates, which provide another way of reusing code. Class templates let you define a class in generic terms. Then you can use the template to create specific classes defined for specific types. For example, you could define a general stack template and then use the template to create one class representing a stack of int values and another class representing a stack of double values. You could even generate a class representing a stack of stacks. Classes with Object Members Let's begin with classes that include class objects as members. Some classes, such as the This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. String class of Chapter 12, "Classes and Dynamic Memory Allocation," or the standard C++ classes and templates of Chapter 16, "The string Class and the Standard Template Library," offer convenient ways of representing components of a more extensive class. We'll look at a particular example now. What is a student? Someone enrolled in a school? Someone engaged in thoughtful investigation? A refugee from the harsh exigencies of the real world? Someone with an identifying name and a set of quiz scores? Clearly, the last definition is a totally inadequate characterization of a person, but it is well-suited for a simple computer representation. So let's develop a Student class based on that definition. Simplifying a student to a name and a set of quiz scores suggests using a String class object (Chapter 12) to hold the name and an array class object (coming up soon) to hold the scores (assumed to be type double). (Once you learn about the library classes discussed in Chapter 16, you probably would use the standard string and vector classes.) You might be tempted to publicly derive a Student class from these two classes. That would be an example of multiple public inheritance, which C++ allows, but it would be inappropriate here. The reason is that the relationship of a student to these classes doesn't fit the is-a model. A student is not a name. A student is not an array of quiz scores. What we have here is a has-a relationship. A student has a name, and a student has an array of quiz scores. The usual C++ technique for modeling has-a relationships is to use composition or containment; that is, to create a class composed of, or containing, members that are objects of another class. For example, we can begin a Student class declaration like this: class Student { private: String name; // use a String object for name ArrayDb scores; // use an ArrayDb object for scores }; As usual, the class makes the data members private. This implies that the Student class member functions can use the public interfaces of the String and ArrayDb (for array of double) classes to access and modify the name and scores objects, but that the outside world cannot do so. The only access the outside world will have to name and scores is through the public interface defined for the Student class (see Figure 14.1). A common This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. way of describing this is saying that the Student class acquires the implementation of its member objects, but doesn't inherit the interface. For example a Student object uses the String implementation rather than a char * name or a char name[26] implementation for holding the name. But a Student object does not innately have the ability to use the String operator==() function. Figure 14.1. Containment. Interfaces and Implementations With public inheritance, a class inherits an interface, and, perhaps, an implementation. (Pure virtual functions in a base class can provide an interface without an implementation.) Acquiring the interface is part of the is-a relationship. With composition, on the other hand, a class acquires the implementation without the interface. Not inheriting the interface is part of the has-a relationship. This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. The fact that a class object doesn't automatically acquire the interface of a contained object is a good thing for a has-a relationship. For example, one could extend the String class to overload the + operator to allow concatenating two strings, but, conceptually, it doesn't make sense to concatenate two Student objects. That's one reason not to use public inheritance in this case. On the other hand, parts of the interface for the contained class may make sense for the new class. For example, you might want to use the operator<() method from the String interface to sort Student objects by name. You can do so by defining a Student::Operator<() member function that, internally, uses the String::Operator<() function. Let's move on to some details. The ArrayDb Class The first detail is developing the ArrayDb class so that the Student class can use it. This class will be quite similar to the String class because the latter is an array, too, in this case, of char. First, let's list some necessary and/or desirable features for the ArrayDb class. It should be able to store several double values. It should provide random access to individual values using bracket notation with an index. One can assign one array to another. The class will perform bounds checking to ensure that array indices are valid. The first two features are the essence of an array. The third feature is not true of built-in arrays but is true for class objects, so creating an array class will provide that feature. The final feature, again, is not true for built-in arrays, but can be added as part of the second feature. At this point, much of the design can ape the String declaration, replacing type char with type double. That is, you can do this: class ArrayDb { private: This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. unsigned int size; // number of array elements double * arr; // address of first element public: ArrayDb(); // default constructor // create an ArrayDb of n elements, set each to val ArrayDb(unsigned int n, double val = 0.0); // create an ArrayDb of n elements, initialize to array pn ArrayDb(const double * pn, unsigned int n); ArrayDb(const ArrayDb & a); // copy constructor virtual ~ArrayDb(); // destructor double & operator[](int i); // array indexing const double & operator[](int i) const; // array indexing // other stuff to be added here ArrayDb & operator=(const ArrayDb & a); friend ostream & operator<<(ostream & os, const ArrayDb & a); }; The class will use dynamic memory allocation to create an array of the desired size. Therefore, it also will provide a destructor, a copy constructor, and an assignment operator. For convenience, it will have a few more constructors. Tweaking operator[]() To provide random access using array notation, the class has to overload the [] operator, just as the String class did. This will allow code like the following: ArrayDb scores(5, 20.0); // 5 elements, each set to 20.0 double temp = scores[3]; scores[3] = 16.5: Clients of the ArrayDB class can access array elements individually only through the overloaded [] operator. This gives you the opportunity to build in some safety checks. In particular, the method can check to see if the proposed array index is in bounds. That is, you can write the operator this way: double & ArrayDb::operator[](int i) { This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. // check index before continuing if (i < 0 || i >= size) { cerr << "Error in array limits: " << i << " is a bad index\n"; exit(1); } return arr[i]; } This slows down a program, for it requires evaluating an if statement every time the program accesses an array element. But it adds safety, preventing a program from placing a value in the 2000th element of a 5-element array. As with the String class, we need a const version of the [] operator to allow read-only access for constant ArrayDb objects: const double & ArrayDb::operator[](int i) const { // check index before continuing if (i < 0 || i >= size) { cerr << "Error in array limits: " << i << " is a bad index\n"; exit(1); } return arr[i]; } The compiler will select the const version of operator[]() for use with const ArrayDb objects and use the other version for non-const ArrayDb objects. Listing 14.1 shows the header file for the ArrayDb class. For extra convenience, the class definition includes an Average() method that returns the average of the array elements. Listing 14.1 arraydb.h This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. [...]... second argument Then assignment would replace the original doh with the temporary object With explicit in place, the compiler will catch the assignment operator as an error Real World Note: C++ and Constraints C++ is full of features that allow the programmer to constrain programmatic constructs to certain limits—explicit to remove the implicit conversion of single-argument constructors, const to constrain... ArrayDb(const double *, int) constructor What happens if you don't use the initialization-list syntax? As with inherited components, C++ requires that all member objects be constructed before the rest of an object is constructed So if you omit the initialization list, C++ will use the default constructors defined for the member objects classes Initialization Order When you have a member initializer... place; the maintenance programmer can't derive a method to mangle the data, because you've protected him If he tries, his compiler stops him, and forces him to create his method as const also Use of the C++ language to prevent disaster by generating compiler errors is a sure sign of an experienced, thoughtful programmer The features exist to help, and using them to their utmost is, in the long run, sure . place, the compiler will catch the assignment operator as an error. Real World Note: C++ and Constraints C++ is full of features that allow the programmer to constrain programmatic constructs. with inherited components, C++ requires that all member objects be constructed before the rest of an object is constructed. So if you omit the initialization list, C++ will use the default constructors defined. Thanks. String class of Chapter 12, "Classes and Dynamic Memory Allocation," or the standard C++ classes and templates of Chapter 16, "The string Class and the Standard Template Library,"

Ngày đăng: 07/07/2014, 06:20

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN