?? ch17.htm
字號:
34:
35: String & operator= (const String &);
36: int GetLen()const { return itsLen; }
37: const char * GetString() const { return itsString; }
38: BOOL Invariants() const;
39:
40: private:
41: String (int); // private constructor
42: char * itsString;
43: // unsigned short itsLen;
44: int itsLen;
45: };
46:
47: // default constructor creates string of 0 bytes
48: String::String()
49: {
50: itsString = new char[1];
51: itsString[0] = `\0';
52: itsLen=0;
53: ASSERT(Invariants());
54: }
55:
56: // private (helper) constructor, used only by
57: // class methods for creating a new string of
58: // required size. Null filled.
59: String::String(int len)
60: {
61: itsString = new char[len+1];
62: for (int i = 0; i<=len; i++)
63: itsString[i] = `\0';
64: itsLen=len;
65: ASSERT(Invariants());
66: }
67:
68: // Converts a character array to a String
69: String::String(const char * const cString)
70: {
71: itsLen = strlen(cString);
72: itsString = new char[itsLen+1];
73: for (int i = 0; i<itsLen; i++)
74: itsString[i] = cString[i];
75: itsString[itsLen]='\0';
76: ASSERT(Invariants());
77: }
78:
79: // copy constructor
80: String::String (const String & rhs)
81: {
82: itsLen=rhs.GetLen();
83: itsString = new char[itsLen+1];
84: for (int i = 0; i<itsLen;i++)
85: itsString[i] = rhs[i];
86: itsString[itsLen] = `\0';
87: ASSERT(Invariants());
88: }
89:
90: // destructor, frees allocated memory
91: String::~String ()
92: {
93: ASSERT(Invariants());
94: delete [] itsString;
95: itsLen = 0;
96: }
97:
98: // operator equals, frees existing memory
99: // then copies string and size
100: String& String::operator=(const String & rhs)
101: {
102: ASSERT(Invariants());
103: if (this == &rhs)
104: return *this;
105: delete [] itsString;
106: itsLen=rhs.GetLen();
107: itsString = new char[itsLen+1];
108: for (int i = 0; i<itsLen;i++)
109: itsString[i] = rhs[i];
110: itsString[itsLen] = `\0';
111: ASSERT(Invariants());
112: return *this;
113: }
114:
115: //non constant offset operator, returns
116: // reference to character so it can be
117: // changed!
118: char & String::operator[](int offset)
119: {
120: ASSERT(Invariants());
121: if (offset > itsLen)
122: return itsString[itsLen-1];
123: else
124: return itsString[offset];
125: ASSERT(Invariants());
126: }
127:
128: // constant offset operator for use
129: // on const objects (see copy constructor!)
130: char String::operator[](int offset) const
131: {
132: ASSERT(Invariants());
133: if (offset > itsLen)
134: return itsString[itsLen-1];
135: else
136: return itsString[offset];
137: ASSERT(Invariants());
138: }
139:
140:
141: BOOL String::Invariants() const
142: {
143: #ifdef SHOW_INVARIANTS
144: cout << " String OK ";
145: #endif
146: return ( (itsLen && itsString) ||
147: (!itsLen && !itsString) );
148: }
149:
150: class Animal
151: {
152: public:
153: Animal():itsAge(1),itsName("John Q. Animal")
154: {ASSERT(Invariants());}
155: Animal(int, const String&);
156: ~Animal(){}
157: int GetAge() { ASSERT(Invariants()); return itsAge;}
158: void SetAge(int Age)
159: {
160: ASSERT(Invariants());
161: itsAge = Age;
162: ASSERT(Invariants());
163: }
164: String& GetName()
165: {
166: ASSERT(Invariants());
167: return itsName;
168: }
169: void SetName(const String& name)
170: {
171: ASSERT(Invariants());
172: itsName = name;
173: ASSERT(Invariants());
174: }
175: BOOL Invariants();
176: private:
177: int itsAge;
178: String itsName;
179: };
180:
181: Animal::Animal(int age, const String& name):
182: itsAge(age),
183: itsName(name)
184: {
185: ASSERT(Invariants());
186: }
187:
188: BOOL Animal::Invariants()
189: {
190: #ifdef SHOW_INVARIANTS
191: cout << " Animal OK ";
192: #endif
193: return (itsAge > 0 && itsName.GetLen());
194: }
195:
196: int main()
197: {
198: Animal sparky(5,"Sparky");
199: cout << "\n" << sparky.GetName().GetString() << " is ";
200: cout << sparky.GetAge() << " years old.";
201: sparky.SetAge(8);
202: cout << "\n" << sparky.GetName().GetString() << " is ";
203: cout << sparky.GetAge() << " years old.";
204: return 0;
<TT>205: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: String OK String OK String OK String OK String OK
String OK String OK Animal OK String OK Animal OK
Sparky is Animal OK 5 years old. Animal OK Animal OK
Animal OK Sparky is Animal OK 8 years old. String OK
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>On lines 6-16, the <TT>assert()</TT>
macro is defined. If <TT>DEBUG</TT> is defined, this will write out an error message
when the <TT>assert()</TT> macro evaluates <TT>FALSE</TT>.<BR>
On line 38, the <TT>String</TT> class member function <TT>Invariants()</TT> is declared;
it is defined on lines 141-148. The constructor is declared on lines 48-54, and on
line 53, after the object is fully constructed, <TT>Invariants()</TT> is called to
confirm proper construction.</P>
<P>This pattern is repeated for the other constructors, and the destructor calls
<TT>Invariants()</TT> only before it sets out to destroy the object. The remaining
class functions call <TT>Invariants()</TT> both before taking any action and then
again before returning. This both affirms and validates a fundamental principal of
C++: Member functions other than constructors and destructors should work on valid
objects and should leave them in a valid state.</P>
<P>On line 175, class <TT>Animal</TT> declares its own <TT>Invariants()</TT> method,
implemented on lines 188-194. Note on lines 154, 157, 160, and 162 that inline functions
can call the <TT>Invariants()</TT> method.
<H4 ALIGN="CENTER"><A NAME="Heading36"></A><FONT COLOR="#000077">Printing Interim
Values</FONT></H4>
<P>In addition to asserting that something is true using the <TT>assert()</TT> macro,
you may want to print the current value of pointers, variables, and strings. This
can be very helpful in checking your assumptions about the progress of your program,
and in locating off-by-one bugs in loops. Listing 17.7 illustrates this idea.</P>
<P><A NAME="Heading37"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 17.7. Printing
values in DEBUG mode.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">1: // Listing 17.7 - Printing values in DEBUG mode
2: #include <iostream.h>
3: #define DEBUG
4:
5: #ifndef DEBUG
6: #define PRINT(x)
7: #else
8: #define PRINT(x) \
9: cout << #x << ":\t" << x << endl;
10: #endif
11:
12: enum BOOL { FALSE, TRUE } ;
13:
14: int main()
15: {
16: int x = 5;
17: long y = 73898l;
18: PRINT(x);
19: for (int i = 0; i < x; i++)
20: {
21: PRINT(i);
22: }
23:
24: PRINT (y);
25: PRINT("Hi.");
26: int *px = &x;
27: PRINT(px);
28: PRINT (*px);
29: return 0;
<TT>30: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: x: 5
i: 0
i: 1
i: 2
i: 3
i: 4
y: 73898
"Hi.": Hi.
px: 0x2100 (You may receive a value other than 0x2100)
*px: 5
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>The macro on lines 5-10 provides
printing of the current value of the supplied parameter. Note that the first thing
fed to <TT>cout</TT> is the stringized version of the parameter; that is, if you
pass in <TT>x</TT>, <TT>cout</TT> receives <TT>"x"</TT>.<BR>
<BR>
Next, <TT>cout</TT> receives the quoted string <TT>":\t"</TT>, which prints
a colon and then a tab. Third, <TT>cout</TT> receives the value of the parameter
(<TT>x</TT>), and then finally, <TT>endl</TT>, which writes a new line and flushes
the buffer.
<H4 ALIGN="CENTER"><A NAME="Heading39"></A><FONT COLOR="#000077">Debugging Levels</FONT></H4>
<P>In large, complex projects, you may want more control than simply turning <TT>DEBUG</TT>
on and off. You can define debug levels and test for these levels when deciding which
macros to use and which to strip out.</P>
<P>To define a level, simply follow the <TT>#define DEBUG</TT> statement with a number.
While you can have any number of levels, a common system is to have four levels:
<TT>HIGH</TT>, <TT>MEDIUM</TT>, <TT>LOW</TT>, and <TT>NONE</TT>. Listing 17.8 illustrates
how this might be done, using the <TT>String</TT> and <TT>Animal</TT> classes from
Listing 17.6. The definitions of the class methods other than <TT>Invariants()</TT>
have been left out to save space because they are unchanged from Listing 17.6.
<BLOCKQUOTE>
<P>
<HR>
<FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>To compile this code, copy lines
43-136 of Listing 17.6 between lines 64 and 65 of this listing.
<HR>
</BLOCKQUOTE>
<P><A NAME="Heading40"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 17.8. Levels
of debugging.</B></FONT></P>
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -