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

Beginning Visual C plus plus phần 4 doc

123 168 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 123
Dung lượng 2 MB

Nội dung

<< “Coordinates of Hut2 are “ << Hut2.Left << “,” << Hut2.Top << “ and “ << Hut2.Right << “,” << Hut2.Bottom; cout << endl << “The area of the yard is “ << Area(Yard); cout << endl << “The area of the pool is “ << Area(Pool) << endl; return 0; } // Function to calculate the area of a rectangle long Area(RECTANGLE& aRect) { return (aRect.Right - aRect.Left)*(aRect.Bottom - aRect.Top); } // Function to Move a Rectangle void MoveRect(RECTANGLE& aRect, int x, int y) { int length = aRect.Right - aRect.Left; // Get length of rectangle int width = aRect.Bottom - aRect.Top; // Get width of rectangle aRect.Left = x; // Set top left point aRect.Top = y; // to new position aRect.Right = x + length; // Get bottom right point as aRect.Bottom = y + width; // increment from new position return; } The output from this example is: Coordinates of Hut2 are 10,90 and 35,110 The area of the yard is 12000 The area of the pool is 1600 How It Works Note that the struct definition appears at global scope in this example. You’ll be able to see it in the Class View tab for the project. Putting the definition of the struct at global scope allows you to declare a variable of type RECTANGLE anywhere in the .cpp file. In a program with a more significant amount of code, such definitions would normally be stored in a .h file and then added to each .cpp file where nec- essary by using a #include directive. You have defined two functions to process RECTANGLE objects. The function Area() calculates the area of the RECTANGLE object that you pass as a reference argument as the product of the length and the width, where the length is the difference between the horizontal positions of the defining points, and the 328 Chapter 7 10_571974 ch07.qxp 1/20/06 11:44 PM Page 328 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com width is the difference between the vertical positions of the defining points. By passing a reference, the code runs a little faster because the argument is not copied. The MoveRect() function modifies the defining points of a RECTANGLE object to position it at the coordinates x, y which are passed as argu- ments. The position of a RECTANGLE object is assumed to be the position of the Left, Top point. Because the RECTANGLE object is passed as a reference, the function is able to modify the members of the RECT- ANGLE object directly. After calculating the length and width of the RECTANGLE object passed, the Left and Top members are set to x and y respectively, and the new Right and Bottom members are calcu- lated by incrementing x and y by the length and width of the original RECTANGLE object. In the main() function, you initialize the Yard and Pool RECTANGLE variables with their coordinate positions as shown in Figure 7-1. The variable Hut1 represents the hut at the top-right in the illustration and its members are set to the appropriate values using assignment statements. The variable Hut2, cor- responding to the hut at the bottom-left of the yard, is first set to be the same as Hut1 in the assignment statement Hut2 = Hut1; // Define Hut2 the same as Hut1 This statement results in the values of the members of Hut1 being copied to the corresponding members of Hut2. You can only assign a struct of a given type to another of the same type. You can’t increment a struct directly or use a struct in an arithmetic expression. To alter the position of Hut2 to its place at the bottom-left of the yard, you call the MoveRect() function with the coordinates of the required position as arguments. This roundabout way of getting the coordi- nates of Hut2 is totally unnecessary and serves only to show how you can use a struct as an argument to a function. Intellisense Assistance with Structures You’ve probably noticed that the editor in Visual C++ 2005 is quite intelligent — it knows the types of variables, for instance. If you hover the mouse cursor over a variable name in the editor window, it pop ups a little box showing its definition. It also can help a lot with structures (and classes, as you will see) because not only does it know the types of ordinary variables, it also knows the members that belong to a variable of a particular structure type. If your computer is reasonably fast, as you type the member selection operator following a structure variable name, the editor pops a window showing the list of members. If you click one of the members, it shows the comment that appeared in the original definition of the structure, so you know what it is. This is shown in Figure 7-2 using a fragment of the previous example. Figure 7-2 329 Defining Your Own Data Types 10_571974 ch07.qxp 1/20/06 11:44 PM Page 329 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Now there’s a real incentive to add comments, and to keep them short and to the point. If you double- click on a member in the list or press the Enter key when the item is highlighted, it is automatically inserted after the member selection operator, thus eliminating one source of typos in your code. Great, isn’t it? You can turn any or all of the Intellisense features off if you want to via the Tools > Options menu item, but I guess the only reason you would want to is if your machine is too slow to make them useful. You can turn the statement-completion features on or off on the C/C++ editor page that you select in the right options pane. If you turn them off, you can still call them up when you want too, either through the Edit menu or through the keyboard. Pressing Ctrl+J, for example, pops up the members for an object under the cursor. The editor also shows the parameter list for a function when you are typing the code to call it — it pops up as soon as you enter the left parenthesis for the argument list. This is particu- larly helpful with library functions as its tough to remember the parameter list for all of them. Of course, the #include directive for the header file must already be there in the source code for this to work. Without it the editor has no idea what the library function is. You will see more things that the editor can help with as you learn more about classes. After that interesting little diversion, let’s get back to structures. The struct RECT Rectangles are used a great deal in Windows programs. For this reason, there is a RECT structure prede- fined in the header file windows.h. Its definition is essentially the same as the structure that you defined in the last example: struct RECT { int left; // Top left point int top; // coordinate pair int right; // Bottom right point int bottom; // coordinate pair }; This struct is usually used to define rectangular areas on your display for a variety of purposes. Because RECT is used so extensively, windows.h also contains prototypes for a number of functions to manipulate and modify rectangles. For example, windows.h provides the function InflateRect() to increase the size of a rectangle and the function EqualRect() to compare two rectangles. MFC also defines a class called CRect, which is the equivalent of a RECT structure. After you understand classes, you will be using this in preference to the RECT structure. The CRect class provides a very exten- sive range of functions for manipulating rectangles, and you will be using a number of these when you are writing Windows programs using MFC. Using Pointers with a struct As you might expect, you can create a pointer to a variable of a structure type. In fact, many of the func- tions declared in windows.h that work with RECT objects require pointers to a RECT as arguments 330 Chapter 7 10_571974 ch07.qxp 1/20/06 11:44 PM Page 330 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com because this avoids the copying of the whole structure when a RECT argument is passed to a function. To define a pointer to a RECT object for example, the declaration is what you might expect: RECT* pRect = NULL; // Define a pointer to RECT Assuming that you have defined a RECT object, aRect, you can set the pointer to the address of this vari- able in the normal way, using the address-of operator: pRect = &aRect; // Set pointer to the address of aRect As you saw when the idea of a struct was introduced, a struct can’t contain a member of the same type as the struct being defined, but it can contain a pointer to a struct, including a pointer to a struct of the same type. For example, you could define a structure like this: struct ListElement { RECT aRect; // RECT member of structure ListElement* pNext; // Pointer to a list element }; The first element of the ListElement structure is of type RECT, and the second element is a pointer to a structure of type ListElement — the same type as that being defined. (Remember that this element isn’t of type ListElement, it’s of type ‘pointer to ListElement’.) This allows object of type ListElement to be daisy-chained together, where each ListElement can contain the address of the next ListElement object in a chain, the last in the chain having the pointer as zero. This is illustrated in Figure 7-3. Figure 7-3 Each box in the diagram represents an object of type ListElement and the pNext member of each object stores the address of the next object in the chain, except for the last object where pNext is 0. This kind of arrangement is usually referred to as a linked list. It has the advantage that as long as you know the first element in the list, you can find all the others. This is particularly important when variables are created dynamically, since a linked list can be used to keep track of them all. Every time a new one is cre- ated, it’s simply added to the end of the list by storing its address in the pNext member of the last object in the chain. LE1 members: aRect pnext = &LE2 LE4 members: aRect pnext = &LE5 LE2 members: aRect pnext = &LE3 LE3 members: aRect pnext = &LE4 LE5 No next element members: aRect pnext = 0 331 Defining Your Own Data Types 10_571974 ch07.qxp 1/20/06 11:44 PM Page 331 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Accessing Structure Members through a Pointer Consider the following statements: RECT aRect = { 0, 0, 100, 100 }; RECT* pRect = &aRect; The first declares and defines the aRect object to be of type RECT with the first pair of members initial- ized to (0, 0) and the second pair to (100, 100). The second statement declares pRect as a pointer to type RECT and initializes it with the address of aRect. You can now access the members of aRect through the pointer with a statement such as this: (*pRect).Top += 10; // Increment the Top member by 10 The parentheses to de-reference the pointer here are essential because the member access operator takes precedence over the de-referencing operator. Without the parentheses, you would be attempting to treat the pointer as a struct and to de-reference the member, so the statement would not compile. After exe- cuting this statement, the Top member will have the value 10 and, of course, the remaining members will be unchanged. The method that you used here to access the member of a struct through a pointer looks rather clumsy. Because this kind of operation crops up very frequently in C++, the language includes a special operator to enable you to express the same thing in a much more readable and intuitive form, so let’s look at that next. The Indirect Member Selection Operator The indirect member selection operator, ->, is specifically for accessing members of a struct through a pointer; this operator is also referred to as the indirect member access operator. The operator looks like a little arrow (->)and is formed from a minus sign (-) followed by the symbol for greater than (>) You could use it to rewrite the statement to access the Top member of aRect through the pointer pRect, as follows: pRect->Top += 10; // Increment the Top member by 10 This is much more expressive of what is going on, isn’t it? The indirect member selection operator is also used with classes, and you’ll be seeing a lot more of it throughout the rest of the book. Data Types, Objects, Classes and Instances Before I get into the language, syntax, and programming techniques of classes, I’ll start by considering how your existing knowledge relates to the concept of classes. So far, you’ve learned that native C++ lets you create variables that can be any of a range of fundamental data types: int, long, double and so on. You have also seen how you can use the struct keyword to define a structure that you could then use as the type for a variable representing a composite of several other variables. 332 Chapter 7 10_571974 ch07.qxp 1/20/06 11:44 PM Page 332 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com The variables of the fundamental types don’t allow you to model real-world objects (or even imaginary objects) adequately. It’s hard to model a box in terms of an int, for example; however, you can use the members of a struct to define a set of attributes for such an object. You could define variables, length, width, and height to represent the dimensions of the box and bind them together as members of a Box structure, as follows: struct Box { double length; double width; double height; }; With this definition of a new data type called Box, you define variables of this type just as you did with variables of the basic types. You can then create, manipulate, and destroy as many Box objects as you need to in your program. This means that you can model objects using structs and write your pro- grams around them. So—that’s object-oriented programming all wrapped up then? Well, not quite. You see, object-oriented programming (OOP) is based on a number of foundations (famously encapsulation, polymorphism, and inheritance) and what you have seen so far doesn’t quite fit the bill. Don’t worry about what these terms mean for the moment — you’ll be exploring that in the rest of this chapter and throughout the book. The notion of a struct in C++ goes far beyond the original concept of struct in C — it incorporates the object-oriented notion of a class. This idea of classes, from which you can create your own data types and use them just like the native types, is fundamental to C++, and the new keyword class was intro- duced into the language to describe this concept. The keywords struct and class are almost identical in C++, except for the access control to the members, which you will find out more about later in this chapter. The keyword struct is maintained for backwards compatibility with C, but everything that you can do with a struct and more, you can achieve with a class. Take a look at how you might define a class representing boxes: class CBox { public: double m_Length; double m_Width; double m_Height; }; When you define CBox as a class you are essentially defining a new data type, similar to when you defined the Box structure. The only differences here are the use of the keyword class instead of struct, and the use of the keyword public followed by a colon that precedes the definition of the members of the class. The variables that you define as part of the class are called data members of the class, because they are variables that store data. You have also called the class CBox instead of Box. You could have called the class Box, but the MFC adopts the convention of using the prefix C for all class names, so you might as well get used to it. MFC also prefixes data members of classes with m_ to distinguish them from other variables, so I’ll use this 333 Defining Your Own Data Types 10_571974 ch07.qxp 1/20/06 11:44 PM Page 333 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com convention too. Remember though that in other contexts where you might use C++ and in C++/CLI in particular, this will not be the case; in some instances the convention for naming classes and their mem- bers may be different, and in others there may be no particular convention adopted for naming entities. The public keyword is a clue as to the difference between a structure and a class. It just defines the members of the class as being generally accessible, in the same way as the members of a structure are. The members of a struct, however, are public by default. As you’ll see a little later in the chapter, though, it’s also possible to place restrictions on the accessibility of the class members. You can declare a variable, bigBox say, that represents an instance of the CBox class type like this: CBox bigBox; This is exactly the same as declaring a variable for a struct, or indeed for any other variable type. After you have defined the class CBox, declarations for variables of this type are quite standard. First Class The notion of class was invented by an Englishman to keep the general population happy. It derives from the theory that people who knew their place and function in society would be much more secure and comfortable in life than those who did not. The famous Dane, Bjarne Stroustrup, who invented C++, undoubtedly acquired a deep knowledge of class concepts while at Cambridge University in England and appropriated the idea very successfully for use in his new language. Class in C++ is similar to the English concept, in that each class usually has a very precise role and a per- mitted set of actions. However, it differs from the English idea because class in C++ has largely socialist overtones, concentrating on the importance of working classes. Indeed, in some ways it is the reverse of the English ideal, because, as you will see, working classes in C++ often live on the backs of classes that do nothing at all. Operations on Classes In C++ you can create new data types as classes to represent whatever kinds of objects you like. As you’ll come to see, classes (and structures) aren’t limited to just holding data; you can also define mem- ber functions or even operations that act between objects of your classes using the standard C++ opera- tors. You can define the class CBox, for example, so that the following statements work and have the meanings you want them to have: CBox box1; CBox box2; if(box1 > box2) // Fill the larger box box1.fill(); else box2.fill(); You could also implement operations as part of the CBox class for adding, subtracting or even multiply- ing boxes — in fact, almost any operation to which you could ascribe a sensible meaning in the context of boxes. 334 Chapter 7 10_571974 ch07.qxp 1/20/06 11:44 PM Page 334 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com I’m talking about incredibly powerful medicine here and it constitutes a major change in the approach that you can take to programming. Instead of breaking down a problem in terms of what are essentially computer-related data types (integer numbers, floating point numbers and so on) and then writing a program, you’re going to be programming in terms of problem-related data types, in other words classes. These classes might be named CEmployee, or CCowboy, or CCheese, or CChutney, each defined specifically for the kind of problem that you want to solve, complete with the functions and operators that are necessary to manipulate instances of your new types. Program design now starts with deciding what new application-specific data types you need to solve the problem in hand and writing the program in terms of operations on the specifics that the problem is con- cerned with, be it CCoffins or CCowpokes. Terminology I’ll first summarize some of the terminology that I will be using when discussing classes in C++: ❑ A class is a user-defined data type. ❑ Object-oriented programming (OOP) is the programming style based on the idea of defining your own data types as classes. ❑ Declaring an object of a class type is sometimes referred to as instantiation because you are cre- ating an instance of a class. ❑ Instances of a class are referred to as objects. ❑ The idea of an object containing the data implicit in its definition, together with the functions that operate on that data, is referred to as encapsulation. When I get into the detail of object-oriented programming, it may seem a little complicated in places, but getting back to the basics of what you’re doing can often help to make things clearer, so always keep in mind what objects are really about. They are about writing programs in terms of the objects that are spe- cific to the domain of your problem. All the facilities around classes in C++ are there to make this as comprehensive and flexible as possible. Let’s get down to the business of understanding classes. Understanding Classes A class is specification of a data type that you define. It can contain data elements that can either be vari- ables of the basic types in C++, or of other user-defined types. The data elements of a class may be single data elements, arrays, pointers, arrays of pointers of almost any kind, or objects of other classes, so you have a lot of flexibility in what you can include in your data type. A class also can contain functions that operate on objects of the class by accessing the data elements that they include. So, a class combines both the definition of the elementary data that makes up an object and the means of manipulating the data that belongs to individual objects of the class. The data and functions within a class are called members of the class. Humorously enough, the mem- bers of a class that are data items are called data members and the members that are functions are called function members or member functions. The member functions of a class are also sometimes referred to as methods; I will not use this term in this book but keep it in mind as you may see it used elsewhere. 335 Defining Your Own Data Types 10_571974 ch07.qxp 1/20/06 11:44 PM Page 335 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com The data members are also referred to as fields, and this terminology is used with C++/CLI, so I will be using this terminology from time to time. When you define a class, you define a blueprint for a data type. This doesn’t actually define any data but it does define what the class name means, that is, what an object of the class will consist of and what operations can be performed on such an object. It’s much the same as if you wrote a description of the basic type double. This wouldn’t be an actual variable of type double, but a definition of how it’s made up and how it operates. To create a variable of a basic data type, you need to use a declaration statement. It’s exactly the same with classes, as you will see. Defining a Class Take a look again at the class example mentioned earlier—a class of boxes. You defined the CBox data type using the keyword class as follows: class CBox { public: double m_Length; // Length of a box in inches double m_Width; // Width of a box in inches double m_Height; // Height of a box in inches }; The name of the class appears following the class keyword, and the three data members are defined between the curly braces. The data members are defined for the class using the declaration statements that you already know and love and the whole class definition is terminated with a semicolon. The names of all the members of a class are local to the class. You can therefore use the same names else- where in a program without causing any problems. Access Control in a Class The public keyword looks a bit like a label, but in fact it is more than that. It determines the access attributes of the members of the class that follow it. Specifying the data members as public means that these members of an object of the class can be accessed anywhere within the scope of the class object to which they belong. You can also specify the members of a class as private or protected. In fact, if you omit the access specification altogether, the members have the default attribute, private. (This is the only difference between a class and a struct in C++ — the default access specifier for a struct is public.) You will be looking into the effect of these keywords in a class definition a bit later. Remember that all you have defined so far is a class, which is a data type. You haven’t declared any objects of the class type. When I talk about accessing a class member, say m_Height, I’m talking about accessing the data member of a particular object, and that object needs to be declared somewhere. Declaring Objects of a Class You declare objects of a class with exactly the same sort of declaration that you use to declare objects of basic types, so you could declare objects of the CBox class type with these statements: CBox box1; // Declare box1 of type CBox CBox box2; // Declare box2 of type CBox 336 Chapter 7 10_571974 ch07.qxp 1/20/06 11:44 PM Page 336 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Both of the objects box1 and box2 will, of course, have their own data members. This is illustrated in Figure 7-4. Figure 7-4 The object name box1 embodies the whole object, including its three data members. They are not initial- ized to anything, however — the data members of each object will simply contain junk values, so we need to look at how you can access them for the purpose of setting them to some specific values. Accessing the Data Members of a Class You can refer to the data members of objects of a class using the direct member selection operator that you used to access members of a struct. So, to set the value of the data member m_Height of the object box2 to, say, 18.0, you could write this assignment statement: box2.m_Height = 18.0; // Setting the value of a data member You can only access the data member in this way in a function that is outside the class because the m_Height member was specified as having public access. If it wasn’t defined as public, this statement would not compile. You’ll see more about this shortly. Try It Out Your First Use of Classes Verify that you can use your class in the same way as the structure. Try it out in the following console application: // Ex7_02.cpp // Creating and using boxes #include <iostream> using std::cout; using std::endl; class CBox // Class definition at global scope { public: double m_Length; // Length of a box in inches double m_Width; // Width of a box in inches double m_Height; // Height of a box in inches }; int main() { CBox box1; // Declare box1 of type CBox box1 m_Length 8 bytes 8 bytes 8 bytes m_Width m_Height box2 m_Length 8 bytes 8 bytes 8 bytes m_Widthm_Height 337 Defining Your Own Data Types 10_571974 ch07.qxp 1/20/06 11:44 PM Page 337 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... of a class for that object Try It Out Adding a Member Function to CBox To see how you access the members of the class from within a function member, create an example extending the CBox class to include a member function that calculates the volume of the CBox object // Ex7_03.cpp // Calculating the volume of a box with a member function #include using std::cout; using std::endl; class CBox... for a constructor is necessary or permitted Try It Out Adding a Constructor to the CBox class Let’s extend our CBox class to incorporate a constructor // Ex7_ 04. cpp // Using a constructor #include using std::cout; using std::endl; class CBox { public: double m_Length; double m_Width; double m_Height; // Class definition at global scope // Length of a box in inches // Width of a box in inches... from the compiler, of course Amongst a lot of other stuff, you get these useful comments from the compiler: warning C4 520: ‘CBox’: multiple default constructors specified error C2 668: ‘CBox::CBox’: ambiguous call to overloaded function This means that the compiler can’t work out which of the two constructors to call — the one for which you have set default values for the parameters or the constructor that... the current object Try It Out Explicit Use of this You could add a public function to the CBox class that compares the volume of two CBox objects // Ex7_10.cpp // Using the pointer this #include using std::cout; using std::endl; class CBox // Class definition at global scope { public: // Constructor definition CBox(double lv = 1.0, double bv = 1.0, double hv = 1.0) { cout . the two calls of the constructor CBox(), once for each object declared. The constructor that you have supplied in the class definition is automatically called when a CBox object is declared,. extend our CBox class to incorporate a constructor. // Ex7_ 04. cpp // Using a constructor #include <iostream> using std::cout; using std::endl; class CBox // Class definition at global scope { public: double. of the specific object used to call the function, and the function can only be called for a particular object of the class. In this case, this is done by using the direct member access operator

Ngày đăng: 12/08/2014, 10:21