EDIT: specific example at the bottom
The best way to explain the problem is by example (note that solutions for this specific example aren't the answers I'm looking for).
Say I have a base class Base
, which is basically a container:
class Base {
protected:
class BaseNode {
protected:
BaseNode* next;
int id;
};
Node* head;
public:
// ... functionality
};
And now I want to derive and improve it, adding an extra data field:
class Derived : public Base {
private:
class DerivedNode: public BaseNode {
char* name;
};
public:
// .. some more functionality
};
What I want is a Derived
class with all the functionality of Base
, but have every node also include a name
, not just an id
.
But if I look at an instance of DerivedNode
, what I want would be:
DerivedNode = {
DerivedNode* next;
int id;
char* name;
};
But what I have is:
DerivedNode = {
BaseNode* next;
int id;
char* name;
};
So DerivedNode()->next->name
would be undefined!
Not to mention that the Base
class only handles BaseNode
s... all calls to new
and delete
wouldn't allocate enough memory for the char*
in DerivedNode
.
This seems like a very generic problem, is there some neat way of solving this? Most of Base
s functionality would be really useful even for DerivedNode
s, so I would prefer to keep the inheritance scheme as it is...
Edit: A specific example for when this may be useful
I don't really want to put lots of code, so I'll try to explain... I've asked a question regarding my specific needs here if anyone wants to see an example.
I'm implementing a List
class. That is my base class. It is templated (the data in each node is templated, and each node also has *next and *prev fields), has an iterator nested class, insertion, removal by iterator location... the works.
I want to implement a Forrest
class, which is a list of data node (still templated), but each node includes a list of TreeNode
s that point to the node. I want to do this because the data is sortable and I want to be able to fetch it in log(n)
time (hence, a tree), but it is sortable in two different ways (say, age and ID number), so I need two tree pointing to the same data.
So: I made Forrest
inherit from List
, and derived ForrestNode
to include a list of TreeNode
s that point to the data:
class DerivedNode: public List<T>::ListNode {
List<Tree<T*>::TreeNode*> treeNodes;
};
The base class List
doesn't need to know about the new treeNodes
field, because it is irrelevant to the lists functionality - methods like swap
, get_head
, is_empty
should work the same, and creating a new node should work pretty much the same (need to allocate more memory, but the new treeNodes
field should never be initialized with data).
The new Forrest
class, however, will override the base List
s methods, but only with added functionality - for example, after insertion (regular list insertion), a pointer will be inserted into the relevant tree, and then the address of the new tree node will be added to the treeNodes
list.
You can simply turn your Base::BaseNode into a template and provide the type of the
next
member variable as the type argument, like so: