0

I have a non-templatized class (Par_list_elem), and I would like to give access to its internals to the class Par_list (to build an intrusive list).

The catch: I need Par_list_elem and all of its subclasses to be accessible to Par_list. In detail, the only fields that need to be accessible are _next and _prev; explicitly limiting to those fields would be nice, but isn't required.

I've made a few preliminary attempts at doing this, the latest of which is below:

        template <class T> class Par_list {
            public:

                    Par_list() : _head(0) {}
                    ~Par_list();

                    //Insert element into list
                    bool insert(T elem);


                    //Remove element identified by iterator
                    void erase(iterator itr);

            private:
                    T* _head;
    };


    class Par_list_elem {
            public:
                    Par_list_elem() : _next(0), _prev(0) {}
                    //Get next element in list
                    Par_list_elem* next() { return _next; }

            private:
                    Par_list_elem* _next;
                    Par_list_elem* _prev;

                    template <typename> friend class Par_list;
    };




    template <class T> void Par_list<T>::erase(Par_list<T>::iterator itr) {

        T* e = *itr;

        T* p;
        if ((p = e->_prev) != 0)
                p->_next = e->_next;
        else
                _head = e->_next;

        if ((e->_next) != 0)
                (e->_next)->_prev = p;

        delete e;
    }

    template <class T> bool Par_list<T>::insert(T* nelem) {

        T* curr = _head;
        if (curr != 0)  {
                while (curr->_next != 0)
                        curr = curr->next();
                curr->_next = nelem;
        } else
                _head = nelem;

        nelem->_prev = curr;
        nelem->_next = 0;

        return true;
}

test.cpp

#include "parsnip_list_back.h"

class elem : parsnip::Par_list_elem {
    int _elem;
};

int main (int argc, char** argv) {

    parsnip::Par_list<elem> plist;

    return 0;
}

Some information seems to be available here: Template friend But the goal is different in enough detail that I'm stuck.

Thanks!

--------UPDATE---------

The following sort of error occurs for each instance of an access of a private member of Par_list_elem. I'm compiling on gcc 4.4.

parsnip_list_back.h:66: error: ‘parsnip::Par_list_elem* parsnip::Par_list_elem::_prev’ is private
parsnip_list_back.h:124: error: within this context

So, with the current implementation, even the superclass isn't giving up its privates.

Community
  • 1
  • 1
bcr
  • 1,328
  • 11
  • 27
  • That doesn't really make sense; you say you need access to "all of its subclasses", but then that you only need access to the fields defined in the base class - which is exactly what the `friend` declaration in your code gives you. What exactly is the problem? – Mike Seymour Jul 28 '11 at 01:35
  • Par_class cannot access the _next and _prev fields of subclasses of Par_list_elem. Does that make sense? – bcr Jul 28 '11 at 01:39
  • It should be able to, since they are members of the class with the `friend` declaration, not of the subclass, and it did when I tried it. What compiler are you using? What error are you getting? Could you post an example of a subclass of `Par_list_elem`, and some code in `Par_list` that tries to access one of these members? – Mike Seymour Jul 28 '11 at 01:45
  • I've updated the original post with some additional information. I should have been a bit clearer about what was wrong: the superclass isn't friendly at this point either. Additionally, here is an example subclass which is being compiled with the above code, but currently (key) isn't reporting any errors: `class elem : Par_list_elem { int _elem; };` – bcr Jul 28 '11 at 04:50
  • Please make a complete, self-contained, minimal example that illustrates your problem. Code you posted doesn't even reference any private members. Your error messages refer to code that you didn't post. It is impossible to say what are you doing wrong. – n. m. could be an AI Jul 28 '11 at 05:13
  • Thanks for the feedback & patience. I've updated the original post. – bcr Jul 28 '11 at 06:08

1 Answers1

1

The problem is that you're inheriting privately from Par_list_elem. So, although Par_list can access private members of the base class, it cannot access the base class itself.

I need Par_list_elem and all of its subclasses to be accessible to Par_list.

This would solve the problem if it were possible, but it can't be done; friendship isn't inherited.

The simplest solution is to inherit publicly.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • So the idea is that because elem inherits publicly, Par_list is guaranteed that the original private _next and _prev fields won't be tinkered with by subclasses, so it's o.k. for Par_list to use them? Also: Thanks so much! Worked like a charm. – bcr Jul 28 '11 at 06:29
  • Okay, my last comment was confused. Because the only base class members (ignoring next() for simplicity) are private, member accessibility isn't modified by the inheritance access specifier. So only public inheritance provides access to the base class itself? And access to the base class itself is the only way to recover friends of the base class? – bcr Jul 28 '11 at 06:55