Previous Table of Contents Next


Weighing the Pluses and Minuses

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 C’s built-in types. Keeping that in mind, I recommend that you avoid using C++ classes unless they’ve 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, it’s better to enter this realm of C++ programming slowly and cautiously. And, even after developing some mastery over OOP, it’s a good idea to resist the seduction of C++ features, like operator overloading, that look clever, but increase—rather than reduce—program complexity. following these guidelines can help the pluses of C++ outnumber the minuses.

C Coding Suggestions

*  Use // for comments everywhere but in macro definitions.
*  Use const variables or enumerations, instead of macros, to define mnemonics for constant values.
*  Use in-line functions and templates instead of function-like macros.
*  Define all member functions outside their respective class declaration.
*  Use in-line functions sparingly.
*  Use REF and other macros to define & and other C++ symbols.
*  Use the C++ new and delete operators instead of the malloc() and free() functions.
*  Where possible, use C++ stream I/O instead of the standard C library routines.
*  In a complex expression, use parentheses to explicitly define how the expression is evaluated.
*  Understand the lifetime of object data.
*  Implement assignment functions so that the same object can appear on both sides of the = operator.
*  Avoid overloading operators other than =.

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