?? ch09.htm
字號:
<TT> cout << "pVar's value is " << pVar << "." << endl;</TT><TT> cout << "*pVar's value is " << *pVar << "." << endl;</TT><TT> return 0;</TT><TT>}</TT></FONT></PRE><P>It's important to remember that the pointer does not contain a variable's value,only its address. The indirection operator enables you to refer to the value storedat the address instead of to the address itself.</P><P>As shown in Listing 9.4, a pointer variable is declared using the indirectionoperator, like this:</P><PRE><FONT COLOR="#0066FF"><TT>int* pVar; // declare a pointer to int</TT></FONT></PRE><BLOCKQUOTE> <P><HR><B> </B><FONT COLOR="#000077"><B>CAUTION:</B></FONT><B> </B>If you are in the habit of declaring several variables on one line, look out for pointer declarations. The indirection operator applies only to the object to its immediate right, not to the whole line. The declaration</P> <PRE><FONT COLOR="#0066FF"><TT>int* pFoo, pBar;</TT></FONT></PRE></BLOCKQUOTE><PRE><FONT COLOR="#0066FF"><TT></TT></FONT></PRE><BLOCKQUOTE> <P>declares and defines two variables: a pointer to an <TT>int</TT> named <TT>pFoo</TT>, and an <TT>int</TT> named <TT>pBar</TT>. The <TT>pBar</TT> variable is not a pointer. If you insist on declaring more than one pointer per line, use this style:</BLOCKQUOTE><PRE></PRE><BLOCKQUOTE> <P><FONT COLOR="#0066FF"><TT>int *pFoo, *pBar;</TT></FONT> <HR></BLOCKQUOTE><PRE></PRE><P>Pointers are useful when you must change a parameter inside a function. Becauseparameters are always passed by value, the only way to change the value of a parameterinside a function is to send the address of the variable to the function, as Listing9.5 does.<H4><FONT COLOR="#000077">TYPE: Listing 9.5. Using a pointer and a function to changea variable's value.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>#include <iostream></TT><TT>using namespace std;</TT><TT>void IncrementVar( int* pVar );</TT><TT>int main()</TT><TT>{</TT><TT> int nVar = 0;</TT><TT> cout << "The value of nVar is now " << nVar << "." << endl;</TT><TT> IncrementVar( &nVar );</TT><TT> cout << "The value of nVar is now " << nVar << "." << endl;</TT><TT> return 0;</TT><TT>}</TT><TT>void IncrementVar( int* nVar )</TT><TT>{</TT><TT> *nVar += 1;</TT><TT>}</TT></FONT></PRE><P>Figure 9.4 shows how the address is used to change the value of a variable outsidethe function.</P><P><A NAME="04"></A><A HREF="04.htm"><B>Figure 9.4.</B> </A><I><BR>Changing a variable's address outside a function.</I></P><P>Another use for pointers is to keep a reference to memory that has been requestedat runtime from the operating system. You will use pointers like this later, in thesection called "Using <TT>new</TT> and <TT>delete</TT> to Create Dynamic Objects."<H3><FONT COLOR="#000077"><B>Using References</B></FONT></H3><P>In addition to using pointers to refer to other variables, the C++ language alsohas a derived type known as a <I>reference</I>. A reference is declared using thereference operator <TT>&</TT>, which bears an uncanny resemblance to the address-ofoperator. Both operators use the same symbol; however, you use them in differentcontexts. The only time <TT>&</TT> is used for a reference is in a declaration,like this:</P><PRE><FONT COLOR="#0066FF"><TT>int myAge;</TT><TT>int& myRef = myAge;</TT></FONT></PRE><P>This code defines a reference variable named <TT>myRef</TT>, which is a reference,or <I>alias</I>, for the <TT>myAge</TT> variable. The advantage of using a referenceinstead of a pointer variable is that no indirection operator is required. However,after it is defined, the reference variable cannot be bound to another variable.For example, code such as that in Listing 9.6 often is misunderstood.<H4><FONT COLOR="#000077">TYPE: Listing 9.6. Using references to change the valueof a variable.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>void refFunc()</TT><TT>{</TT><TT> int nFoo = 5;</TT><TT> int nBar = 10;</TT><TT> // Define a reference to int that is an alias for nFoo.</TT><TT> int& nRef = nFoo;</TT><TT> // Change the value of nFoo.</TT><TT> nRef = nBar;</TT><TT> CString strMsg;</TT><TT> strMsg.Format("nFoo = %d, nBar = %d", nFoo, nBar);</TT><TT> AfxMessageBox(strMsg);</TT><TT>}</TT></FONT></PRE><P>If you use the <TT>refFunc</TT> function in a Windows program, you will see thatthe line</P><PRE><FONT COLOR="#0066FF"><TT>nRef = nFoo;</TT></FONT></PRE><P>does not change the binding of the <TT>nRef</TT> variable; instead, it assignsthe value of <TT>nBar</TT> to <TT>nFoo</TT>, with <TT>nFoo</TT> being the variableto which <TT>nRef</TT> is a reference.</P><P>References are most commonly used when passing parameters to functions. Passinga class object as a function parameter often is quite expensive in terms of computingresources. Using a pointer to pass a parameter is subject to errors and affects thefunction's readability. However, if you use references as function parameters, youeliminate unnecessary copies, and you can use the parameter as if a copy were passed.To prevent the called function from changing the value of a reference variable, youcan declare the parameter as <TT>const</TT>, like this:</P><PRE><FONT COLOR="#0066FF"><TT>void Print( const int& nFoo )</TT><TT>{</TT><TT> nFoo = 12; // error - not allowed to change const</TT><TT> cout << "The value is " << nFoo << endl;</TT><TT>}</TT></FONT></PRE><BLOCKQUOTE> <P><HR><B> </B><FONT COLOR="#000077"><B>]Time Saver:</B></FONT><B> </B>References to <TT>const</TT> objects are often used when large objects are passed to a function because it can be expensive, in terms of computing resources, to generate a copy of a large object that is used only during a function call. <HR></BLOCKQUOTE><H3><FONT COLOR="#000077"><B>Using <TT>new</TT> and <TT>delete</TT> to Create DynamicObjects</B></FONT></H3><P>So far, you've learned about variables allocated as local objects that are createdwhen a function or block is entered and destroyed when the function or block is exited.Most programs that work in the real world use variables and objects that have a <I>dynamiclifetime</I>, meaning that they are explicitly created and explicitly destroyed.</P><P>In a C++ program, you can use the <TT>new</TT> and <TT>delete</TT> operators toallocate and destroy variables dynamically, as shown in Listing 9.7.<H4><FONT COLOR="#000077">TYPE: Listing 9.7. Using new and delete for fundamentaltypes.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>void ptrFunc()</TT><TT>{</TT><TT> int *pFoo = new int;</TT><TT> *pFoo = 42;</TT><TT> CString strMsg;</TT><TT> strMsg.Format("Foo = %d", *pFoo);</TT><TT> AfxMessageBox(strMsg);</TT><TT> delete pFoo;</TT><TT>}</TT></FONT></PRE><H3><FONT COLOR="#000077"><B>Using <TT>new[]</TT> and <TT>delete[]</TT> to CreateArrays</B></FONT></H3><P>You also can create arrays dynamically using <TT>new[]</TT>, with the size ofthe array specified inside the square brackets. When you create an array using <TT>new[]</TT>,you must use <TT>delete[]</TT> to release the memory allocated for the array. Thesize of the array is not specified when <TT>delete[]</TT> is used. Using <TT>delete[]</TT>is the only clue to the compiler indicating that the pointer is the beginning ofan array of objects. Listing 9.8 is an example of a function showing how to allocateand free a dynamic array.<H4><FONT COLOR="#000077">TYPE: Listing 9.8. Using new[] to create a dynamic array.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>void ptrArrayFunc()</TT><TT>{</TT><TT> // Create array</TT><TT> const int nMaxFoo = 5;</TT><TT> int *arFoo = new int[nMaxFoo];</TT><TT> // Fill array</TT><TT> for(int n = 0; n < nMaxFoo; n++)</TT><TT> {</TT><TT> arFoo[n] = 42 + n;</TT><TT> }</TT><TT> // Read array</TT><TT> for(n = 0; n < nMaxFoo; n++ )</TT><TT> {</TT><TT> CString strMsg;</TT><TT> strMsg.Format("Index %d = %d", n, arFoo[n]);</TT><TT> AfxMessageBox(strMsg);</TT><TT> }</TT><TT> // Free array</TT><TT> delete[] arFoo;</TT><TT>}</TT></FONT></PRE><P>Note that in Listing 9.8, it's possible to use a variable to specify the sizeof the array.<H3><FONT COLOR="#000077"><B>Using Pointers with Derived Classes</B></FONT></H3><P>An instance of a class can be allocated and used dynamically, just as if it wereone of the fundamental types, like this:</P><PRE><FONT COLOR="#0066FF"><TT>CRect* pRect = new CRect;</TT></FONT></PRE><P>This example allocates space for a <TT>CRect</TT> object and calls the <TT>CRect</TT>constructor to perform any needed initializations. Of course, after the <TT>CRect</TT>object is no longer needed, you should make sure that the program calls <TT>delete</TT>to free the allocated memory and cause the class's destructor to be called.</P><PRE><FONT COLOR="#0066FF"><TT>delete pRect;</TT></FONT></PRE><P>When using a pointer to a class or structure, you use the member selection operator,or <TT>-></TT>, to access member data and functions:</P><PRE><FONT COLOR="#0066FF"><TT>pRect->left = 0;</TT><TT>int nHeight = pRect->Height();</TT></FONT></PRE><H3><FONT COLOR="#000077"><B>Using a Pointer to a Base Class</B></FONT></H3><P>Because a class derived from a base class actually contains the base, it's possibleto use a pointer to a base class when working with a derived object. For example,in the MFC library, you can use a pointer to a <TT>CWnd</TT> object in place of a<TT>CDialog</TT> object. This makes a design much easier to implement because allthe functions that work with any type of window can just use pointers to <TT>CWnd</TT>instead of trying to determine the type of each object. In other words, because <TT>CDialog</TT>is a <TT>CWnd</TT>, you should be able to do this:</P><PRE><FONT COLOR="#0066FF"><TT>CWnd* pWnd = new CDialog(/*Initialization info deleted*/;</TT><TT>pWnd->EnableWindow();</TT></FONT></PRE><P>You might be wondering how this code works--after all, how does the compiler knowto call the <TT>CWnd</TT> version of <TT>EnableWindow</TT> or the <TT>CDialog</TT>version of <TT>EnableWindow</TT>? In order to solve this problem, you must declarefunctions used through base-class pointers as virtual functions. When a functionis declared with the <TT>virtual</TT> keyword, the compiler generates code that determinesthe actual type of the object at runtime and calls the correct function.<H3><FONT COLOR="#000077"><B>Using Virtual Functions</B></FONT></H3><P><FONT COLOR="#000077"><B>New Term:</B></FONT><B> </B>A <I>virtual function</I>is a function that is resolved at runtime.</P><P>When a virtual function is used, the compiler constructs a special table, calleda <I>virtual function table</I>. This table is used to keep track of the correctfunctions to be called for every object of that class. When a virtual function iscalled, the virtual function table is used to access the correct function indirectly,as shown in Figure 9.5.</P><P><A NAME="05"></A><A HREF="05.htm"><B>Figure 9.5.</B></A> <I><BR>The virtual function table, used to determine the correct virtual function.</I></P><P>The added overhead of using the virtual function table is fairly small, but itcould be significant if you have thousands of small objects or if execution speedis critical. For that reason, a function must be specified as <TT>virtual</TT>; itdoesn't happen by default. Listing 9.9 is an example of a class declaration thatuses a virtual function.<H4><FONT COLOR="#000077">TYPE: Listing 9.9. An example of declaring a virtual function.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>class CUser</TT><TT>{</TT><TT>public:</TT><TT> CUser();</TT><TT> virtual void ClearInfo();</TT><TT>protected:</TT><TT> // ...</TT><TT>};</TT></FONT></PRE><BLOCKQUOTE> <P><HR><B> </B><FONT COLOR="#000077"><B>Time Saver:</B></FONT><B> </B>The <TT>virtual</TT> keyword is used only in the class declaration, not in the function definition. <HR></BLOCKQUOTE><P><FONT COLOR="#000077"><B>New Term:</B></FONT><B> </B>When a base class declaresa virtual function, it sometimes makes no sense for the base class to provide anyimplementation for the function. A base class that includes functions that are declared,but are implemented in derived classes, is an <I>abstract class</I>.</P><P>To force all subclasses of a class to implement a virtual function, you can declarethat function as a "pure" virtual function by adding <TT>= 0;</TT> to itsdeclaration in the abstract class, as shown in Listing 9.10.<H4><FONT COLOR="#000077">TYPE: Listing 9.10. An example of declaring a pure virtualfunction.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT>class CShape</TT><TT>{</TT><TT>public:</TT><TT> virtual void Draw() = 0;</TT><TT>};</TT></FONT></PRE><H2><FONT COLOR="#000077"><B>Exploring Document/View Interfaces</B></FONT></H2><P>The most commonly used interfaces in a Document/View program handle communicationbetween the document and view objects, and between Windows and the document and viewobjects. Each of these interfaces has a particular purpose. Some are always overriddenin the classes you include in your project; many are overridden only when needed.These are three of the major interfaces used in a Document/View program:<UL> <LI><TT>GetDocument</TT>, a <TT>CView</TT> member function used to retrieve a pointer to its document<BR> <BR> <LI><TT>UpdateAllViews</TT>, a <TT>CDocument</TT> member function used to update views associated with a document<BR> <BR> <LI><TT>OnNewDocument</TT>, a <TT>CDocument</TT> member function used to initialize the document's member data</UL><P>Remember, this list is just an overview of the major interfaces. The list doesnot cover all the interfaces required in an SDI or MDI program. Your mileage mayvary; after using the Document/View architecture for a while, you might have another
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -