📄 ch17.htm
字号:
43: // unsigned short itsLen;44: int itsLen;45: };46: 47: // default constructor creates string of 0 bytes48: 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 by57: // class methods for creating a new string of58: // 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 String69: 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 constructor80: 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 memory91: String::~String ()92: {93: ASSERT(Invariants());94: delete [] itsString;95: itsLen = 0;96: }97: 98: // operator equals, frees existing memory99: // then copies string and size100: 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, returns116: // reference to character so it can be117: // changed!118: char & String::operator[](int offset)119: {120: ASSERT(Invariants());121: if (offset > itsLen)122: return itsString[itsLen-1];123: else124: return itsString[offset];125: ASSERT(Invariants());126: }127: 128: // constant offset operator for use129: // on const objects (see copy constructor!)130: char String::operator[](int offset) const131: {132: ASSERT(Invariants());133: if (offset > itsLen)134: return itsString[itsLen-1];135: else136: return itsString[offset];137: ASSERT(Invariants());138: }139: 140: 141: BOOL String::Invariants() const142: {143: #ifdef SHOW_INVARIANTS144: cout << " String OK ";145: #endif146: return ( (itsLen && itsString) || 147: (!itsLen && !itsString) );148: }149: 150: class Animal151: {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_INVARIANTS191: cout << " Animal OK ";192: #endif193: 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 OKSparky 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 messagewhen 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 online 53, after the object is fully constructed, <TT>Invariants()</TT> is called toconfirm 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 remainingclass functions call <TT>Invariants()</TT> both before taking any action and thenagain before returning. This both affirms and validates a fundamental principal ofC++: Member functions other than constructors and destructors should work on validobjects 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 functionscan call the <TT>Invariants()</TT> method.<H4 ALIGN="CENTER"><A NAME="Heading36"></A><FONT COLOR="#000077">Printing InterimValues</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. Thiscan 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. Printingvalues in DEBUG mode.</B></FONT></P><PRE><FONT COLOR="#0066FF">1: // Listing 17.7 - Printing values in DEBUG mode2: #include <iostream.h>3: #define DEBUG4:5: #ifndef DEBUG6: #define PRINT(x)7: #else8: #define PRINT(x) \9: cout << #x << ":\t" << x << endl;10: #endif11: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: 5i: 0i: 1i: 2i: 3i: 4y: 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 providesprinting of the current value of the supplied parameter. Note that the first thingfed to <TT>cout</TT> is the stringized version of the parameter; that is, if youpass 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 printsa 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 flushesthe 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 whichmacros 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 illustrateshow this might be done, using the <TT>String</TT> and <TT>Animal</TT> classes fromListing 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. Levelsof debugging.</B></FONT></P><PRE><FONT COLOR="#0066FF">0: enum LEVEL { NONE, LOW, MEDIUM, HIGH };1: const int FALSE = 0;2: const int TRUE = 1;3: typedef int BOOL;4: 5: #define DEBUGLEVEL HIGH6: 7: #include <iostream.h>8: #include <string.h>9: 10: #if DEBUGLEVEL < LOW // must be medium or high11: #define ASSERT(x)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -