⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mi30.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frameset.dtd">
<HTML LANG="EN">
<HEAD>
<TITLE>More Effective C++ | Item 30: Proxy classes</TITLE>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>

<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var imagemax = 0; setCurrentMax(0);</SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">
var dingbase = "MI30_DIR.HTM";
var dingtext = "Item M30, P";
if (self == top) {
 top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>

</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="M30: Proxy classes" -->
<A NAME="6074"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./MI29_FR.HTM" TARGET="_top">Item 29: Reference counting</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./MI31_FR.HTM" TARGET="_top">Item 31: Making functions virtual with respect to more than one object</A></FONT></DIV>


<A NAME="dingp1"></A><P><font ID="mititle">Item 30: &nbsp;Proxy classes.</font><SCRIPT>create_link(1);</SCRIPT>
</P>

<A NAME="72183"></A>

<A NAME="dingp2"></A><P><A NAME="24741"></A>
Though your in-laws may be one-dimensional, the world, in general, is not. Unfortunately, C++ hasn't yet caught on to that fact. At least, there's little evidence for it in the language's support for arrays. You can create two-dimensional, three-dimensional &#151; heck, you can create n-dimensional &#151; arrays in FORTRAN, in BASIC, even in COBOL (okay, FORTRAN only allows up to seven dimensions, but let's not quibble), but can you do it in C++? Only sometimes, and even then only sort of.
<SCRIPT>create_link(2);</SCRIPT>
</P>

<A NAME="dingp3"></A><P><A NAME="24742"></A>
This much is legal:
<SCRIPT>create_link(3);</SCRIPT>
</P><A NAME="24743"></A>

<UL><PRE>int data[10][20];                          // 2D array: 10 by 20
</PRE>
</UL>

<A NAME="dingp4"></A><P><A NAME="24744"></A>
The corresponding construct using variables as dimension sizes, however, is not:<SCRIPT>create_link(4);</SCRIPT>
</P>

<A NAME="24722"></A>
<UL><PRE>void processInput(int dim1, int dim2)
{
  int data[dim1][dim2];                     // error! array dimensions
  ...                                       // must be known during
}                                           // compilation
</PRE>
</UL>

<A NAME="dingp5"></A><P><A NAME="24723"></A>
<A NAME="p214"></A>It's not even legal for a heap-based allocation:
<SCRIPT>create_link(5);</SCRIPT>
</P><A NAME="24726"></A>

<UL><PRE>int *data =
  new int[dim1][dim2];                      // error!
</PRE>
</UL>

<A NAME="dingp6"></A><P><font ID="mhtitle">Implementing Two-Dimensional Arrays</font><SCRIPT>create_link(6);</SCRIPT>
</P>

<A NAME="dingp7"></A><P><A NAME="85521"></A>
Multidimensional arrays are as useful in C++ as they are in any other language, so it's important to come up with a way to get decent support for them. The usual way is the standard one in C++: create a class to represent the objects we need but that are missing in the language proper. Hence we can define a class template for two-dimensional arrays:
<SCRIPT>create_link(7);</SCRIPT>
</P><A NAME="24768"></A>
<UL><PRE>template&lt;class T&gt;
class Array2D {
public:
  Array2D(int dim1, int dim2);
  ...
<A NAME="76168"></A>
};
</PRE>
</UL>

<A NAME="dingp8"></A><P><A NAME="24772"></A>
Now we can define the arrays we want:
<SCRIPT>create_link(8);</SCRIPT>
</P><A NAME="24773"></A>

<UL><PRE>Array2D&lt;int&gt; data(10, 20);             // fine
<A NAME="24777"></A>
Array2D&lt;float&gt; *data =
  new Array2D&lt;float&gt;(10, 20);          // fine
<A NAME="24780"></A>
void processInput(int dim1, int dim2)
{
  Array2D&lt;int&gt; data(dim1, dim2);       // fine
  ...
}
</PRE>
</UL><A NAME="dingp9"></A><P><A NAME="24786"></A>
<I>Using</I> these array objects, however, isn't quite as straightforward. In keeping with the grand syntactic tradition of both C and C++, we'd like to be able to use brackets to index into our arrays,
<SCRIPT>create_link(9);</SCRIPT>
</P><A NAME="24790"></A>

<UL><PRE>cout &lt;&lt; data[3][6];
</PRE>
</UL><A NAME="dingp10"></A><P><A NAME="24791"></A>
but how do we declare the indexing operator in <CODE>Array2D</CODE> to let us do this?
<SCRIPT>create_link(10);</SCRIPT>
</P>    <A NAME="dingp11"></A><P><A NAME="24792"></A>
Our first impulse might be to declare <CODE>operator[][]</CODE> functions, like this:
<SCRIPT>create_link(11);</SCRIPT>
</P><A NAME="24795"></A>
<UL><PRE><A NAME="p215"></A>template&lt;class T&gt;
class Array2D {
public:
</PRE>
</UL><A NAME="24808"></A>
<UL><PRE>  // declarations that won't compile
  T&amp; operator[][](int index1, int index2);
  const T&amp; operator[][](int index1, int index2) const;
</PRE>
</UL><A NAME="24809"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="24810"></A>
<UL><PRE>};
</PRE>
</UL>

<A NAME="dingp12"></A><P><A NAME="24793"></A>
We'd quickly learn to rein in such impulses, however, because there is no such thing as <CODE>operator[][]</CODE>, and don't think your compilers will forget it. (For a complete list of operators, overloadable and otherwise, see <a href="./MI7_FR.HTM#77702" TARGET="_top">Item 7</A>.) We'll have to do something else.
<SCRIPT>create_link(12);</SCRIPT>
</P>

<A NAME="dingp13"></A><P><A NAME="24829"></A>
If you can stomach the syntax, you might follow the lead of the many programming languages that use parentheses to index into arrays. To use parentheses, you just overload <CODE>operator()</CODE>:
<SCRIPT>create_link(13);</SCRIPT>
</P><A NAME="24833"></A>

<UL><PRE>template&lt;class T&gt;
class Array2D {
public:
</PRE>
</UL><A NAME="24841"></A>
<UL><PRE>  // declarations that will compile
  T&amp; operator()(int index1, int index2);
  const T&amp; operator()(int index1, int index2) const;
</PRE>
</UL><A NAME="24835"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="24836"></A>
<UL><PRE>};
</PRE>
</UL><P><A NAME="24846"></A>
<A NAME="dingp14"></A>Clients then use arrays this way:<SCRIPT>create_link(14);</SCRIPT>
</P><A NAME="24849"></A>
<UL><PRE>cout &lt;&lt; data(3, 6);
</PRE>
</UL>

<A NAME="dingp15"></A><P><A NAME="24847"></A>
This is easy to implement and easy to generalize to as many dimensions as you like. The drawback is that your <CODE>Array2D</CODE> objects don't look like built-in arrays any more. In fact, the above access to element (3, 6) of <CODE>data</CODE> looks, on the face of it, like a function call.
<SCRIPT>create_link(15);</SCRIPT>
</P>

<A NAME="dingp16"></A><P><A NAME="24858"></A>
If you reject the thought of your arrays looking like FORTRAN refugees, you might turn again to the notion of using brackets as the indexing operator. Although there is no such thing as <CODE>operator[][]</CODE>, it is nonetheless legal to write code that appears to use it:
<SCRIPT>create_link(16);</SCRIPT>
</P><A NAME="24872"></A>

<UL><PRE>int data[10][20];
</PRE>
</UL><A NAME="26038"></A>
<UL><PRE>...
</PRE>
</UL><A NAME="24875"></A>
<UL><PRE>cout &lt;&lt; data[3][6];          // fine
</PRE>
</UL>

<A NAME="dingp17"></A><P><A NAME="24882"></A>What gives?<SCRIPT>create_link(17);</SCRIPT>
</P>

<A NAME="dingp18"></A><P><A NAME="24907"></A>
<A NAME="p216"></A>What gives is that the variable <CODE>data</CODE> is not really a two-dimensional array at all, it's a 10-element one-dimensional array. Each of those 10 elements is itself a 20-element array, so the expression <CODE>data[3][6]</CODE> really means <CODE>(data[3])[6]</CODE>, i.e., the seventh element of the array that is the fourth element of <CODE>data</CODE>. In short, the value yielded by the first application of the brackets is another array, so the second application of the brackets gets an element from that secondary array.
<SCRIPT>create_link(18);</SCRIPT>
</P>
<A NAME="dingp19"></A><P><A NAME="24914"></A>
We can play the same game with our <CODE>Array2D</CODE> class by overloading <CODE>operator[]</CODE> to return an object of a new class, <CODE>Array1D</CODE>. We can then overload <CODE>operator[]</CODE> again in <CODE>Array1D</CODE> to return an element in our original two-dimensional array:
<SCRIPT>create_link(19);</SCRIPT>
</P><A NAME="24919"></A>

<UL><PRE>template&lt;class T&gt;
class Array2D {
public:
  class Array1D {
  public:
    T&amp; operator[](int index);
    const T&amp; operator[](int index) const;
    ...
<A NAME="24922"></A>
  };
<A NAME="24933"></A>
  Array1D operator[](int index);
  const Array1D operator[](int index) const;
  ...
<A NAME="24935"></A>
};
</PRE>
</UL>

<A NAME="dingp20"></A><P><A NAME="24931"></A>The following then becomes legal:<SCRIPT>create_link(20);</SCRIPT>
</P><A NAME="24939"></A>

<UL><PRE>Array2D&lt;float&gt; data(10, 20);
</PRE>
</UL><A NAME="24945"></A>
<UL><PRE>...
</PRE>
</UL><A NAME="24942"></A>
<UL><PRE>cout &lt;&lt; data[3][6];          // fine
</PRE>
</UL>

<A NAME="dingp21"></A><P><A NAME="24946"></A>
Here, <CODE>data[3]</CODE> yields an <CODE>Array1D</CODE> object and the <CODE>operator[]</CODE> invocation on that object yields the float in position (3, 6) of the original two-dimensional array.
<SCRIPT>create_link(21);</SCRIPT>
</P>

<A NAME="dingp22"></A><P><A NAME="24949"></A>
Clients of the <CODE>Array2D</CODE> class need not be aware of the presence of the <CODE>Array1D</CODE> class. Objects of this latter class stand for one-dimensional array objects that, conceptually, do not exist for clients of <CODE>Array2D</CODE>. Such clients program as if they were using real, live, honest-to-Allah two-dimensional arrays. It is of no concern to <CODE>Array2D</CODE> clients that those objects must, in order to satisfy the vagaries of C++, be syntactically compatible with one-dimensional arrays of other one-dimensional arrays.
<SCRIPT>create_link(22);</SCRIPT>
</P>

<A NAME="dingp23"></A><P><A NAME="25043"></A>
<A NAME="p217"></A>Each <CODE>Array1D</CODE> object <I>stands for</I> a one-dimensional array that is absent from the conceptual model used by clients of <CODE>Array2D</CODE>. Objects that stand for other objects are often called <I>proxy objects</I>, and the classes that give rise to proxy objects are often called <I>proxy classes</I>. In this example, <CODE>Array1D</CODE> is a proxy class. Its instances stand for one-dimensional arrays that, conceptually, do not exist. (The terminology for proxy objects and classes is far from universal; objects of such classes are also sometimes known as <i>surrogates</i>.)
<SCRIPT>create_link(23);</SCRIPT>
</P>

<A NAME="dingp24"></A><P><font ID="mhtitle">Distinguishing Reads from Writes via <CODE>operator[]
</CODE></font><SCRIPT>create_link(24);</SCRIPT>
</P><A NAME="24940"></A>

<A NAME="dingp25"></A><P>The use of proxies to implement classes whose instances act like multidimensional arrays is common, but proxy classes are more flexible than that. <a href="./MI5_FR.HTM#5970" TARGET="_top">Item 5</A>, for example, shows how proxy classes can be employed to prevent single-argument constructors from being used to perform unwanted type conversions. Of the varied uses of proxy classes, however, the most heralded is that of helping distinguish reads from writes through <CODE>operator[]</CODE>.
<SCRIPT>create_link(25);</SCRIPT>
</P>

<A NAME="dingp26"></A><P><A NAME="25134"></A>
Consider a reference-counted string type that supports <CODE>operator[]</CODE>. Such a type is examined in detail in <a href="./MI29_FR.HTM#6073" TARGET="_top">Item 29</A>. If the concepts behind reference counting have slipped your mind, it would be a good idea to familiarize yourself with the material in that Item now.<SCRIPT>create_link(26);</SCRIPT>
</P>

<A NAME="dingp27"></A><P><A NAME="25164"></A>
A string type supporting <CODE>operator[]</CODE> allows clients to write code like this:
<SCRIPT>create_link(27);</SCRIPT>
</P><A NAME="25165"></A>

<UL><PRE>
String s1, s2;           // a string-like class; the
                         // use of proxies keeps this
                         // class from conforming to
                         // the standard string
...                      // interface
<A NAME="25170"></A>
cout &lt;&lt; s1[5];           // read s1
<A NAME="25171"></A>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -