0

I have the following situation:

I have a List class that is using a ListNode class that is inherited in classes that wants to be put in a list.

struct _List_node_base
{
...
 void _M_hook(_List_node_base* const __position);
 void unhook();
};


template<typename _Tp>
class ListNode : public _List_node_base
{
...
        typedef _Tp* pointer;
public:
 pointer GetNext();
 pointer GetPrev();
};


template<typename _Tp>
class List
{
  ...
};

I also have a HashTable class which similar to lists have a HashNode class. The HashNode use ListNode in order to be put in a list in the appropriate hash slot.

    template<typename _KeyType, typename _ObjectType>
    class HashNode : public ListNode<ObjectType>
    {
...
    public:
          _KeyType GetHashKey()
    };



    template<typename _KeyType, typename _ObjectType, typename _HashFunctionType>
    class HashTable
    {
       //example

     template<typename _KeyType, typename _ObjectType, typename _HashFunctionType>
     void HashTable<_KeyType, _ObjectType, _HashFunctionType>::Insert(_ObjectType *object)
     {
      uint pos = hashFunction(object->GetHashKey(), tableSize);

      hashTable[pos].PushBack(object);
     }

    };

I have a class that wants to be both listable and hashable.

class A : public HashNode<SomeKeyType_t, A>, public ListNode<A>
{
 ...
};

The problem is that the compiles complains about that the members in List_node_base has an ambiguous base of class A.

Both in the Hash class and the List class, they use methods in ListNode and List_node_base directly on class A.

Basically, I want to make class A both hashable and listable but the ListNode functionality of HashNode should not be exposed outside the implementation of class HashTable.

Also the point of the classes are that they must be instrusive, dynamic allocations and copying classes is not allowed. Otherwise this would have been solved by creating a container class.

Alex
  • 1
  • 2
    By your design, HashNode are already ListNode so isn't "class A : HashNode" enough? – MerickOWA Dec 07 '10 at 20:48
  • 1
    It is very hard to design good container library. What's the reason to invent the wheel? Say, Boost.Intrusive already has pretty mature implementation of intrusive containers. – Stas Dec 07 '10 at 20:59
  • **Don't** start your identifiers with an underscore: [what-are-the-rules-about-using-an-underscore](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier/228797#228797). This `_List_node_base` (well nearly every type or template parameter is reserved and even a couple of parameters) is reserved for use by the system. – Martin York Dec 07 '10 at 21:21
  • Most well put [rule for avoiding bad identifiers](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier/228848#228848) – Martin York Dec 07 '10 at 22:24

4 Answers4

3

I'm not sure I like the design, but in any case, you can resolve your issue by using virtual inheritance on _List_node_base.

Dark Falcon
  • 43,592
  • 5
  • 83
  • 98
1

I think a better design would be to avoid inheritance and use something like this instead:

template <typename _KeyType, typename _ObjectType>
struct HashEntry {
    typedef ListNode<HashEntry> Node;

    _KeyType key;
    _ObjectType object;
    ...
};

BTW, _<uppercase-letter>... is reserved for the implementation. You should shouldn't use it in your own symbol names.

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
0

Since HashNode is a derived class of ListNode, you have the same "parent" class twice in the object heirarchy.

Avoid Multiple inheritance of non-abstract classes as much as possible. If you absolutely need a class to be inherited from 2 base classes, you should reevaluate your design pattern and/or look into making interface (abstract) classes that your class can implement.

Zac Howland
  • 15,777
  • 1
  • 26
  • 42
  • Advice like this is too generic to be useful. Though I agree with everything you say technically the use of multiple inheritance is so specific to the situations that this kind of generic advice does not translate it specific situations. – Martin York Dec 07 '10 at 21:20
0

Could you possibly use STL / boost containers holding smart pointers (e.g. boost::shared_ptr) to get round the problem that your classes must be none-copy constructable and non-copy assignable?

Tony Park
  • 1,247
  • 1
  • 9
  • 14
  • Basically I could make the HashNode class a member of class A instead to get around the problem. Often using member classes instead like Boost intrusive algorithms requires that you store a reference to class (class A) in that member object. Boost get around this by doing some strange pointer arithmetic which is compiler dependent. – Alex Dec 07 '10 at 21:20