I'm learning C++ on my own, and I thought a good way to get my hands dirty would be to convert some Java projects into C++, see where I fall down. So I'm working on a polymorphic list implementation. It works fine, except for one strange thing.
The way I print a list is to have the EmptyList
class return "null" (a string, not a pointer), and NonEmptyList
returns a string that's their data concatenated with the result of calling tostring()
on everything else in the list.
I put tostring()
in a protected
section (it seemed appropriate), and the compiler complains about this line (s
is a stringstream
I'm using to accumulate the string):
s << tail->tostring();
Here's the error from the compiler:
../list.h: In member function 'std::string NonEmptyList::tostring() [with T = int]': ../list.h:95: instantiated from here ../list.h:41: error: 'std::string List::tostring() [with T = int]' is protected ../list.h:62: error: within this context
Here's most of list.h
:
template <class T> class List;
template <class T> class EmptyList;
template <class T> class NonEmptyList;
template <typename T>
class List {
public:
friend std::ostream& operator<< (std::ostream& o, List<T>* l){
o << l->tostring();
return o;
}
/* If I don't declare NonEmptyList<T> as a friend, the compiler complains
* that "tostring" is protected when NonEmptyClass tries to call it
* recursively.
*/
//friend class NonEmptyList<T>;
virtual NonEmptyList<T>* insert(T) =0;
virtual List<T>* remove(T) =0;
virtual int size() = 0;
virtual bool contains(T) = 0;
virtual T max() = 0;
virtual ~List<T>() {}
protected:
virtual std::string tostring() =0;
};
template <typename T>
class NonEmptyList: public List<T>{
friend class EmptyString;
T data;
List<T>* tail;
public:
NonEmptyList<T>(T elem);
NonEmptyList<T>* insert(T elem);
List<T>* remove(T elem);
int size() { return 1 + tail->size(); }
bool contains(T);
T max();
protected:
std::string tostring(){
std::stringstream s;
s << data << ",";
/* This fails if List doesn't declare NonEmptyLst a friend */
s << tail->tostring();
return s.str();
}
};
So declaring NonEmptyList
a friend of List
makes the problem go away, but it seems really strange to have to declare a derived class as a friend of a base class.