| 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 |