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.