How to inherit a red black tree from a normal bst - c++

I'm having a gigantic trouble with inheritance. I have a normal node as follows (please, ignore any typo in the code, I do not have it right now, but it compiles fine)
template<typename T>
class Node {
Node<T> *parent, *left, *right;
...//simple methods
}
then, I implement a normal BST using the node I just created:
template<typename T>
class tree {
virtual Node<T>* insert(T value);
...// other methods of tree
}
now I want to make a red black tree, but the code for it is almost the same, so I just try to override, say, insert:
template<typename T>
class rb_node : public node<T> {
int color;
...//methods to retrieve and set the color as well the constructor
}
template<typename T>
class rb_tree : public tree<T> {
Node<T> *insert(T value){
auto z = (rb_node<T>*)tree<T>::insert(value);
while(z->parent()->color() == RED)...
}
since I cast, the z->parent() is recognized as a rb_node, but the parent don't since it was constructed in the base class, so it does not have the color() method. How do I solve this problem that is killing me for almost two weeks??
Obs: if anyone need, my code is at https://github.com/dodonut/Algorithms/tree/master/Data_Structures.
I tried to override the variables of node to rb_node on constructor(but cannot cast nullptr), on the method inside rb_node to return rb_node(but the signature of base class methods is different)

One possible solution might be to have the base tree class also take an optional NodeType template argument? As in
template<typename T, typename NodeT = Node<T>>
class tree
{
...
virtual NodeT* insert(T const& value);
...
};
Then the sub-class could use its special rb_node:
template<typename T>
class rb_tree : public tree<T, rb_node<T>>
{
...
rb_node<T>* insert(T const& value) override;
...
};

Related

Inheriting from a class but using a subclass of an attribute

I have to implement a Red/Black tree (RBTree) in C++, inheriting from a Binary Search Tree (BSTree) class I already created.
The BSTree class contains a Node pointer (Node is a class I created for BSTree) to the tree root.
I want to create a Node subclass called "RBTNode", which contains color attribute and related methods (so RBTNode is subclass of Node), then I want to create the RBTree class inheriting from BSTree, but with the new RBTNode instead of the standard Node.
The structure would be as follows:
BSTree contains Node;
RBTNode is subclass of Node;
RBTree is subclass of BSTree;
RBTree contains RBTNode;
How could I achieve that?
As suggested by Jarod42 in the comments, you can achieve this by making the node type a template parameter for the BSTree class.
Say you have these two node classes:
template<typename KeyT>
class BSNode {
public:
KeyT key;
// ...
};
template<typename KeyT>
class RBNode : public BSNode<KeyT> {
public:
bool color;
};
Then you could add a node type template parameter to BSTree and make it BSNode by default. You can then use RBNode while inheriting in RBTree.
template <typename KeyT, typename NodeT = BSNode<KeyT>>
class BSTree {
protected:
NodeT *root;
};
template <typename KeyT>
class RBTree : public BSTree<KeyT, RBNode<KeyT>> {
// root will be of type RBNode<KeyT>* here
};

How should 'Invalid covariant return types' be handled for iterators and similar situations

I'm trying to make a binary tree class Tree and a binary search tree class BST which inherits from the Tree, as well as iterator nested classes for each, where BST::iterator inherits from Tree::iterator.
Now, the problem is that some of the trees' functions must return an iterator of its own class, such as begin(), end(), search(T), etc. This seems to not compile because Tree::begin() and BST::begin() have "invalid covariant return types".
After researching said topic, I understand what is causing the compiler to complain, but I do not understand why it's not allowed. It seems logical that in this case for example, the Tree should return an object of type Tree::iterator and the BST should return an object of type BST::iterator.
Below is some code which should illustrate what it is I am dealing with.
Tree.h
template <class T>
class Tree {
protected:
class Node {
friend Tree;
T value;
Node* left;
Node* right;
};
Node* root;
public:
class iterator {
friend Tree;
Node* node;
public:
// operators and the like...
};
virtual iterator begin() const;
virtual iterator end() const;
virtual iterator search(const T& value) const;
};
BST.h
#include "Tree.h"
template <class T>
class BST : public Tree<T> {
protected:
class Node : public Tree<T>::Node {
friend BST;
};
using Tree<T>::root;
public:
class iterator : public Tree<T>::iterator {
friend BST;
};
using Tree<T>::begin;
using Tree<T>::end;
virtual iterator search(const T& value) const override;
};
It is clear to me that in this case, search is trying to return a BST<T>::iterator, and that's not allowed, because it's overriding a function which returns a Tree<T>::iterator, however it seems logical to me that this should be allowed, and I am unsure as to how this is supposed to be done.
Also, when BST<T> inherits begin() and end(), I assume it is inheriting them such that they return Tree<T>::iterators, although they should really be returning BST<T>::iterators.
What exactly is it that I'm missing, and how should something like this be achieved?
Polymorphism can only be done through pointer/reference, allowing covariance for return object would introduce slicing.
We cannot neither adding covariance relation to "unrelated" type as smart-pointers. (whereas Base* and Derived* can be covariant, std::unique_ptr<Base> and std::unique_ptr<Derived> cannot :/)
Covariance can be done through pointer/reference though.
One way to work around those restrictions is to have 2 methods, one virtual with supported covariance, and one regular method which uses the virtual one to mimic covariance:
template <typename T>
class Tree {
// ...
// Assuming iterator might be constructed with node.
typename Tree<T>::iterator begin() const { return {node_begin()/*, ...*/}; }
typename Tree<T>::iterator end() const { return {node_begin()/*, ...*/}; }
protected:
virtual typename Tree<T>::node* node_begin() const;
virtual typename Tree<T>::node* node_end() const;
};
template <class T>
class BST : public Tree<T> {
// ...
typename BST<T>::iterator begin() const { return {node_begin()/*, ...*/}; }
typename BST<T>::iterator end() const { return {node_begin()/*, ...*/}; }
protected:
typename BST<T>::node* node_begin() const override; // covariance on pointer
typename BST<T>::node* node_end() const override; // covariance on pointer
};

Container implementation using templates and inheritance

I'm trying to implement a generic ranked tree container by inheriting a basic 2-3 tree container
basic tree is declared as follows :
template<typename T>
class Node{
// etc..
}
template<typename T>
class Tree{
Node* root;
// etc
}
and suppose i wanted to implement a tree of integers, i though i could declare a class as follows :
class RankedNode : public Node<int>{
// ...
}
class RankedTree : public Tree<int>{
RankedNode root*; // for example
// ...
}
The class RankedNode will include additional fields to the class Node, that aid in fast traversal of the tree ( O(log n) ) , and by using inheritance i'll be able to prevent code duplication.
However, i don't know how to go about doing so correctly, any ideas would be appreciated :)
You could start by making Tree a template on N, (the node type), instead of T (the value type):
template<typename T>
class Node{
// etc..
}
template<typename N>
class Tree{
N* root;
// etc
}
This way you could write
class RankedNode : public Node<int>{
// ...
}
class RankedTree : public Tree<RankedNode>{
// RankedNode* root; <- remove this; it is already in Tree<RankedNode>
// ...
}
and add only fields that are really new compared to base classes.

How to use the "Curiously recurring template" pattern

I'm not sure that there is allowed to ask questions like this. But I can't really understand the code which should be used in my program.
The situations is that I have to apply an earlier written class, which is design by some pattern and I have no right to change it. Unfortunately I don't know which patter it is, and neither how to use it.
(The story is about a linked list template.)
The code is something like this:
template<typename T> class LListNode {
public:
LListNode();
void setNext(T*);
...
T* next() const;
};
template<typename T> inline void LListNode<T>::setNext(T* next) {
static_cast<T*>(this)->m_next = next;
}
...
This was the node class, the next is the main list class:
template<typename T> class LList {
public:
LList();
bool isEmpty() const;
...
T* head() const;
...
void push(T*);
...
private:
T* m_head;
T* m_tail;
};
First, I tried to instantiate just the LList class with my own class as template class. But it didn't worked. Than I thought that maybe my own class (which will be stored in the List) should be inherited from the LListNode class. Thats seemed to be a good idea, but then there I got stuck.
How can I define a class which is inherited from another class, which gets the currently defined class as template parameter?
Just to make it clear:
class Foo : LListNode<Foo> {
private:
Foo* m_next;
public:
...
At this point my compiler (gcc (Ubuntu/Linaro 4.6.4-1ubuntu1~12.04) 4.6.4
) is crying:
In instantiation of 'void LListNode<T>::setPrev(T*) [with T = Foo]':
required from LListNode<T>::LListNode() [with T = Foo]'
Foo.h: required from here
LList.h: error: LListNode<Foo>' is an inaccessible base of 'Foo'
You forgot public :
class Foo : public LListNode<Foo> {
private:
Foo* m_next;
public:
...

How do I change a class to a template class?

I need to change the first line to : template <class T> class Node{
class Node {
private:
double data;
Node* next;
public:
Node(double);
virtual ~Node(); //for later use of polymorphismi, review the topic again
friend class Stack; // allows dStack for private member access
};
Node::Node(double data) {
this->data = data;
next = 0;
}
Node::~Node() {
}
but i am unsure of all the internal work i need to change. Do i just need to change the private data member and the public Node function?
I think what you are looking for is something along the lines of the following:
template<typename T>
class Node
{
private:
T data;
Node* next;
public:
Node(const T& d);
virtual ~Node();
// ... etc
};
Note that you will either need to implement the template class inline, in the same file, or include the implementation at the bottom of the header file.
The point is that you change your class so that it can be used for other types except double, for example int, float etc in the same way. If we think of it in more abstractly, you need to use the class for objects of type T, where T can be any of the types mentioned above (or even more).
So, in general, you need to put template <class T> (Setting it as a template class) before your class and replace double with T type.
for class declaration:
template<typename T>
class Node
for class functions implementation:
template<typename T>
Node<T>::Node()