Getting compile errors with Copliens 1994 counted pointer example code
OK, I am reading Copliens C++ Idioms book, and trying to run the handle/body examples in the book. After typing in the code, I am getting compile errors:
Here is the code the String and StringRep classes.
#ifndef _STRINGREP_H_
#define _STRINGREP_H_
#include <stdio.h>
#include <string.h>
class String;
class StringRep {
friend class String;
public:
StringRep() {*(rep = new char[1])='\0';}
StringRep(const StringRep& s) {
::strcpy(rep=new char[::strlen(s.rep)+1], s.rep);
}
~StringRep() { delete [] rep;}
StringRep(const char* s) {
::strcpy(rep=new char[::strlen(s)+1], s);
}
String operator+(const String& s) const {
char *buf = new char[s->length() + length() + 1];
::strcpy(buf, rep);
::strcat (buf, s->rep);
String retval(&buf);
开发者_如何转开发 return retval;
}
int length() const { return ::strlen(rep); }
void print() const {::printf("%s\n", rep); }
private:
StringRep(char ** const r) {
rep = *r;
*r = 0;
count = 1;
};
char *rep;
int count;
};
#endif
#ifndef _STRING_H_
#define _STRING_H_
#include <stdio.h>
#include <string.h>
#include "StringRep.h"
class String {
friend class StringRep;
public:
String operator+(const String& s) const {return *p + s;}
StringRep* operator->() const {return p;}
String() {
(p = new StringRep())->count = 1;
}
String (const String &s) { (p=s.p)->count++;}
String(const char* s) {
(p = new StringRep(s))->count = 1;
}
String operator=(const String& s) {
if (--p->count <=0) delete p;
(p = s.p)->count++;
return *this;
}
~String() { if (--p->count <= 0) delete p;; }
private:
String(char **r) {
p = new StringRep(r);
}
StringRep *p;
};
#endif
And a main.cc
#include <stdio.h>
#include <string.h>
#include "StringRep.h"
#include "String.h"
int main() {
String a("abcd"), b("efgh");
printf("a is "); a->print();
printf("b is "); b->print();
printf("concat of a+b is "); (a+b)->print();
return 0;
}
Compile errors;
GNU C++ version 4.1.2 20080704 (Red Hat 4.1.2-44) (x86_64-redhat-linux)
compiled by GNU C version 4.1.2 20080704 (Red Hat 4.1.2-44).
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 2d02d8750f9b337bb19a7dd5b4e2167e
StringRep.h: In member function 'String StringRep::operator+(const String&) const':
StringRep.h:21: error: return type 'struct String' is incomplete
StringRep.h:22: error: base operand of '->' has non-pointer type 'const String'
StringRep.h:24: error: base operand of '->' has non-pointer type 'const String'
StringRep.h:25: error: variable 'String retval' has initializer but incomplete type
String.h: In member function 'String String::operator+(const String&) const':
String.h:13: error: conversion from 'void' to non-scalar type 'String' requested
I figure that I cannot use String class until it is completely defines. Changing the signature of the function to
String& operator+(const String& s) const {...
solves the first error, but causes the same error to show up where I am creating a new String object
String retval(&buf);
I realize that the book I have is the 1994 reprint that I picked up. So can someone either point me newer code (if C++ coding style has changed) or point out how to fix this?
Thanks
You got a circular reference since StringRep
needs to know the full definition of String
to construct it in operator+
. I advice to not put everything in header files, but just the declarations of the member functions and put the definitions in the .cpp
(or .cc
) file. That should fix it. That is also how code should be split if the class itself and / or the functions are not a template.
You need to pull the definition and declaration of everything apart. If you really want to put them in the header file, you can do so as follows:
<forward declarations, required includes>
<class itself, no functions defined>
<includes for forward declarations that are needed for function bodies>
<function bodies>
That will always work.
You can't include the String header file in the StringRep header file when you also include the StringRep header file in the String header file. This causes a circular inclusion and will prevent your code from compiling.
Think of it as:
StringRep.h loads String.h
which loads StringRep.h
which loads String.h
which loads StringRep.h
which loads ...
You can avoid this by moving the function declarations into the .cpp files and simply forward declaring the String class inside of StringRep.h (which you already do!). It won't actually try and resolve the reference to the String class until it actually compiles the code, by which time the circular inclusion issue will have been avoided.
精彩评论