📄 chapter08.html
字号:
<html><HTML><HEAD> <TITLE>Chapter 8</TITLE> <LINK REL="STYLESHEET" HREF="downey.css" tppabs="http://rocky.wellesley.edu/downey/ost/thinkCS/c++_html/downey.css"></HEAD><BODY><H2>Chapter 8</H2><H1>Structures</H1><BR><BR><H3>8.1 Compound values</H3><P>Most of the data types we have been working with represent a single value---an integer, a floating-point number, a boolean value. <TT>apstring</TT>s are different in the sense that they are made up of smallerpieces, the characters. Thus, <TT>apstring</TT>s are an example of a <B>compound</B> type.</P><P>Depending on what we are doing, we may want to treat a compound type as a single thing (or object), or we may want to access its parts (or instance variables). This ambiguity is useful.</P><P>It is also useful to be able to create your own compound values. C++ provides two mechanisms for doing that: <B>structures</B> and <B>classes</B>.We will start out with structures and get to classes in Chapter 14 (there is not much difference between them).</P><BR><BR><H3>8.2 <TT>Point</TT> objects</H3><P>As a simple example of a compound structure, consider the concept of a mathematical point. At one level, a point is two numbers (coordinates) that we treat collectively as a single object. In mathematical notation, points are often written in parentheses, with a comma separating the coordinates. For example, <TT>(0, 0)</TT> indicates the origin, and <TT>(x, y)</TT> indicates the point <TT>x</TT> units to the right and <TT>y</TT> units up from the origin.</P><P>A natural way to represent a point in C++ is with two <TT>double</TT>s. The question, then, is how to group these two values into a compound object, or structure. The answer is a <TT>struct</TT> definition:</P><PRE>struct Point { double x, y;}; </PRE><P><TT>struct</TT> definitions appear outside of any function definition, usually at the beginning of the program (after the <TT>include</TT> statements).</P><P>This definition indicates that there are two elements in this structure, named <TT>x</TT> and <TT>y</TT>. These elements are called <B>instance variables</B>, for reasons I will explain a little later.</P><P>It is a common error to leave off the semi-colon at the end of a structure definition. It might seem odd to put a semi-colon after a squiggly-brace, but you'll get used to it.</P><P>Once you have defined the new structure, you can create variables with that type:</P><PRE> Point blank; blank.x = 3.0; blank.y = 4.0; </PRE><P>The first line is a conventional variable declaration: <TT>blank</TT> has type <TT>Point</TT>. The next two lines initialize the instance variables of the structure. The ``dot notation'' used here is similar to the syntax for invoking a function on an object, as in <TT>fruit.length()</TT>. Of course, one difference is that function names are always followed by an argument list, even if it is empty.</P><P>The result of these assignments is shown in the following state diagram:</P><P CLASS=1><IMG SRC="images/point.png" tppabs="http://rocky.wellesley.edu/downey/ost/thinkCS/c++_html/images/point.png" ALT="Point Image"></P><P>As usual, the name of the variable <TT>blank</TT> appears outside the box and its value appears inside the box. In this case, that value is a compound object with two named instance variables.</P><BR><BR><H3>8.3 Accessing instance variables</H3><P>You can read the values of an instance variable using the same syntax we used to write them:</P><PRE> int x = blank.x;</PRE><P>The expression <TT>blank.x</TT> means ``go to the object named <TT>blank</TT> and get the value of <TT>x</TT>.'' In this case we assign thatvalue to a local variable named <TT>x</TT>. Notice that there is no conflict between the local variable named <TT>x</TT> and the instance variable named <TT>x</TT>. The purpose of dot notation is to identify <I>which</I> variable you are referring to unambiguously.</P><P>You can use dot notation as part of any C++ expression, so the following arelegal.</P><PRE> cout << blank.x << ", " << blank.y << endl; double distance = blank.x * blank.x + blank.y * blank.y;</PRE><P>The first line outputs <TT>3, 4</TT>; the second line calculates the value 25.</P><BR><BR><H3>8.4 Operations on structures</H3><P>Most of the operators we have been using on other types, like mathematical operators ( <TT>+</TT>, <TT>%</TT>, etc.) and comparison operators (<TT>==</TT>, <TT>></TT>, etc.), do not work on structures. Actually, it is possible to define the meaning of these operators for the new type, but we won't do that in this book.</P><P>On the other hand, the assignment operator <I>does</I> work for structures.It can be used in two ways: to initialize the instance variables of a structureor to copy the instance variables from one structure to another. An initialization looks like this:</P><PRE> Point blank = { 3.0, 4.0 };</PRE><P>The values in squiggly braces get assigned to the instance variables of the structure one by one, in order. So in this case, <TT>x</TT> gets the first value and <TT>y</TT> gets the second.</P><P>Unfortunately, this syntax can be used only in an initialization, not in an assignment statement. So the following is illegal.</P><PRE> Point blank; blank = { 3.0, 4.0 }; // WRONG !!</PRE><P>You might wonder why this perfectly reasonable statement should be illegal, and there is no good answer. I'm sorry.</P><P>On the other hand, it is legal to assign one structure to another. For example:</P><PRE> Point p1 = { 3.0, 4.0 }; Point p2 = p1; cout << p2.x << ", " << p2.y << endl;</PRE><P>The output of this program is <TT>3, 4</TT>.</P><BR><BR><H3>8.5 Structures as parameters</H3><P>You can pass structures as parameters in the usual way. For example,</P><PRE>void printPoint (Point p) { cout << "(" << p.x << ", " << p.y << ")" << endl;}</PRE><P><TT>printPoint</TT> takes a point as an argument and outputs it in the standard format. If you call <TT>printPoint (blank)</TT>, it will output <TT>(3, 4)</TT>.</P><P>As a second example, we can rewrite the <TT>distance</TT> function fromSection 5.2 so that it takes two <TT>Point</TT>s as parameters instead of four <TT>double</TT>s.</P><PRE>double distance (Point p1, Point p2) { double dx = p2.x - p1.x; double dy = p2.y - p1.y; return sqrt (dx*dx + dy*dy);}</PRE><BR><BR><H3>8.6 Call by value</H3><P>When you pass a structure as an argument, remember that the argument and theparameter are not the same variable. Instead, there are two variables (one in the caller and one in the callee) that have the same value, at least initially.For example, when we call <TT>printPoint</TT>, the stack diagram looks like this:</P><P CLASS=1><IMG SRC="images/point2.png" tppabs="http://rocky.wellesley.edu/downey/ost/thinkCS/c++_html/images/point2.png" ALT="Point2 Image"></P><P>If <TT>printPoint</TT> happened to change one of the instance variables of <TT>p</TT>, it would have no effect on <TT>blank</TT>. Of course, there is no reason for <TT>printPoint</TT> to modify its parameter, so this isolation between the two functions is appropriate.</P><P>This kind of parameter-passing is called ``pass by value'' because it is thevalue of the structure (or other type) that gets passed to the function.</P><BR><BR><H3>8.7 Call by reference</H3><P>An alternative parameter-passing mechanism that is available in C++ is called ``pass by reference.'' This mechanism makes it possible to pass a structure to a procedure and modify it.</P><P>For example, you can reflect a point around the 45-degree line by swapping the two coordinates. The most obvious (but incorrect) way to write a <TT>reflect</TT> function is something like this:</P><PRE>void reflect (Point p) // WRONG !!{ double temp = p.x; p.x = p.y; p.y = temp;}</PRE><P>But this won't work, because the changes we make in <TT>reflect</TT> will have no effect on the caller.</P><P>Instead, we have to specify that we want to pass the parameter by reference.We do that by adding an ampersand (<TT>&</TT>) to the parameter declaration:</P><PRE>void reflect (Point& p){ double temp = p.x; p.x = p.y; p.y = temp;}</PRE><P>Now we can call the function in the usual way:</P><PRE> printPoint (blank); reflect (blank); printPoint (blank);</PRE><P>The output of this program is as expected:</P><PRE>(3, 4)(4, 3)</PRE><P>Here's how we would draw a stack diagram for this program:</P><P CLASS=1><IMG SRC="images/point3.png" tppabs="http://rocky.wellesley.edu/downey/ost/thinkCS/c++_html/images/point3.png" ALT="Point3 Image"></P><P>The parameter <TT>p</TT> is a reference to the structure named <TT>blank</TT>. The usual representation for a reference is a dot with anarrow that points to whatever the reference refers to.</P><P>The important thing to see in this diagram is that any changes that <TT>reflect</TT> makes in <TT>p</TT> will also affect <TT>blank</TT>.</P><P>Passing structures by reference is more versatile than passing by value, because the callee can modify the structure. It is also faster, because the system does not have to copy the whole structure. On the other hand, it is less safe, since it is harder to keep track of what gets modified where.Nevertheless, in C++ programs, almost all structures are passed by reference almost all the time. In this book I will follow that convention.</P><BR><BR><H3>8.8 Rectangles</H3><P>Now let's say that we want to create a structure to represent a rectangle.The question is, what information do I have to provide in order to specify a rectangle? To keep things simple let's assume that the rectangle will be oriented vertically or horizontally, never at an angle.</P><P>There are a few possibilities: I could specify the center of the rectangle (two coordinates) and its size (width and height), or I could specify one of the corners and the size, or I could specify two opposing corners.</P><P>The most common choice in existing programs is to specify the upper left corner of the rectangle and the size. To do that in C++, we will define a structure that contains a <TT>Point</TT> and two doubles.</P><PRE>struct Rectangle { Point corner; double width, height;}; </PRE><P>Notice that one structure can contain another. In fact, this sort of thing is quite common. Of course, this means that in order to create a <TT>Rectangle</TT>, we have to create a <TT>Point</TT> first:</P><PRE> Point corner = { 0.0, 0.0 };
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -