Previous | Table of Contents | Next |
The previous examples are by no means the only way you can get yourself in trouble with C++s OOP facilities. In fact, I chose some of the simpler cases to fit within the scope of this book. In Further Reading, I describe several excellent books that delve into the topic more deeply. The main point I want to emphasize is that C++ objects can either simplify or complicate programming, depending on how thoughtfully their classes are implemented. C++ objects are supposed to make working with complex program structures as straightforward as working with Cs built-in types. Keeping that in mind, I recommend that you avoid using C++ classes unless theyve been implemented in a way that makes them safe and simple to use. A program is weakened, not strengthened, by using classes that produce surprising results under some conditions.
The other lesson to be learned from examining the complexities of C++ is that great care and lots of experience is necessary before you can implement complex classes that are safe and simple to use. As a result, its better to enter this realm of C++ programming slowly and cautiously. And, even after developing some mastery over OOP, its a good idea to resist the seduction of C++ features, like operator overloading, that look clever, but increaserather than reduceprogram complexity. following these guidelines can help the pluses of C++ outnumber the minuses.
Figure 1. Partial definition of an OutQ class
class OutQ { OUTQ * hOutQ; // Handle for output queue public: OutQ(char * outqname) {// Constructor hOutQ = open_outq(outqname); } const char * nextname() { OUTQ_ENTRY * tmp_qentry = next_outq_entry(hOutQ); return (tmp_qentry ? tmp_qentry->ofile_name : NULL); } };
Figure 2. Revised OutQ class
class OutQ { OUTQ * hOutQ; // Handle for output queue char HoldName[NAMESIZE]; public: OutQ(char * outqname) { // Constructor hOutQ = open_outq(outqname); } const char * nextname() { OUTQ_ENTRY * tmp_qentry = next_outq_entry(hOutQ); if (! tmp_qentry ) return NULL; strcpy(HoldName, tmp_qentry->ofile_name); return HoldName; } };
Figure 3. Partial definition of a String class
class String { char * strdata; int strlength; public: String(char * cs); // Constructor using standard String& operator=(const String& ss); // Assignment }; c har * MakeString(const char * cs) { char * tmpstr = new char[strlen(cs) + 1]; strcpy(tmpstr, cs); return tmpstr; } String::String(char * cs) { strdata = cs ? MakeString(cs) : NULL; strlength = cs ? strlen(cs) : 0; } String& String::operator=(const String& ss) { delete [] strdata; strdata = ss.strdata ? MakeString(ss.strdata) : NULL; strlength = ss.strdata ? ss.strlength : 0; return * this; }
Figure 4. Revised operator= member function
String& String::operator=(const String& ss) { if (this != &ss) { // Source is not same as target delete [] strdata; strdata = ss.strdata ? MakeString(ss.strdata) : NULL; strlength = ss.strdata ? ss.strlength : 0; } return * this; }
Previous | Table of Contents | Next |