Class inheritance issue - c++

I am trying to implement an AVL tree. Initially I implemented two classes, node and node_AVL as such:
class node{
protected:
int info;
node *l, *r;
public:
node *getRight();
};
class node_AVL : public node{
protected:
int height;
public:
void setHeight(int):
};
The problem arises when for example I try to access the child of a node:
node_AVL *node1 = node2.getRight();
Or
node_AVL node;
node.getRight().setHeight(1);
I get these errors:
Invalid conversion from node* to node_AVL*
Class node has no member setHeight()
How can I solve this?

As the error messages say, this line:
node_AVL *node1 = node2.getRight();
doesn't work because getRight() returns a node*. You could fix this by making node1 a node*, like this:
node *node1 = node2.getRight();
For the second part, you would need to do something like:
node node;
node.getRight()->setHeight(1);
This wouldn't work either since setHeight is a member of node_AVL.
You should maybe redesign your class, bearing in mind what you're trying to accomplish.

Related

C++ class pointer I.e node*

In c++ liked list Why we have to write node pointer like node* without specifying int, double etc. and we can also declare new node pointers in main without using any node class declaration.
class Node {
public:
int data;
Node* next;
};
If its any different kind of pointer then what it is called?
In your code
class Node {
public:
int data;
Node* next;
};
there is only one kind of node, and it has an int for data. That is why you don't need to write Node<int> or Node<double>. But you could change your code
template <typename T>
class Node {
public:
T data;
Node<T>* next;
};
This is called a template, and instead of only having an int for the data you can have any type. But now you have to say what that type is when you declare a variable. E.g.
Node<double>* ptr = new Node<double>();

Inheritance and AVL/BST Trees

Is there any way to use the same insert function for both Bst and Avl tree? The problem is that Bst and Avl have different Node types, but I don't want to make the Bst Node a general case(with height and Node* parent inside, which makes no sense because there is no need of parent and height inside a Bst).
class Bst
{
public:
struct Node
{
int value;
Node* left;
Node* right;
};
Node* insert(Node* node) {/* do stuff using Bst::Node */}
// ...
};
class Avl : public Bst
{
public:
struct Node : public Bst::Node
{
int height;
Node* parent;
};
// now I want that Bst::insert use this Node
// instead of the old one
Node* insert(Node* node)
{
Node* inserted_node = Bst::insert(node);
/* rotations stuff */
return inserted_node;
}
};
Roughly what I'm trying to do is make Bst::Node "virtual".
So, how can I solve the problem of implenting the Avl Tree without rewriting the entire insert function just because Node changed?
Actually I'm also working on this stuff and I think you're very clear to describe what you want.
At the first, it's may be little confuse about the given interface, insert() should not return the pointer of the Node, doesn't it. We may use the findNode() function, which return the pointer of the Node and exactly do this work only.
Back to the main question, may be you can use the template to set your Node type for every function in the BST.
But the BST is not just a abstract interface, which also implement the BST operation, so it's not CRTP..
The pseudo code for now may be the following :
// pre-define :
//parent ptr also alleviate the implementation of BST.
template<typename T>
class BST{
... omit..
protected:
template<typename node_type>
class BST_Node{
public:
T val;
BST_Node *left, *right, *parent;
BST_Node():left{nullptr},
right{nullptr},
parent{nullptr}, val{}{};
// empty {} default to value initialization.
}
... omit ...
}
template<typename T>
class AVL_Node : public BST_Node{
public:
short height;
AVL_Node(T val):BST_Node(val), height(0){};
}
template<typename T>
void insert(T val){
AVL_Node<T> Node(val);
BST<T>::insert_node<AVL_Node>(Node);
AVL_Node<T>* ptr = BST<T>::find_node<AVL_Node>(val);
ptr->height = BST<T>::get_height(ptr);
state = chk_balance(ptr);
switch(state){
case 0: // tree very balance..
break;
case 1:
LL_rotate(ptr);
break;
case 2:
RR_rotate(ptr);
break;
... omit
}
}
# help this post solve your question..
Maybe you want CRTP (in which case you haven't given enough info about your needs for even a rough example, but a simpler less powerful template approach may make more sense to you. Have a base class (under each of your tree types) that has no data members, and just defines static template functions for the common code. Since the functions are static, you need to pass in the relevant data (for insert that should be &root) but that should not be much trouble. (Rough and untested):
struct tree_base
{
template <class Node>
static Node* insert( Node** where, Node* what)
{
Node* here;
while ( (here = *where) != 0 )
{
if ( *what < *here ) where = &(here->left);
else if ( *here < *what ) where = &(here->right);
else
{
Trying to insert something already there, what should be done
}
}
*where = what;
return what; // Is that the desired return?
}
};
Then each of your real tree classes would inherit from tree_base and would call tree_base::insert(&root, new_node) to do the common parts of insert
A CRTP version of that would allow root to be a member of the base class even though it points to the Node type of the derived class. Given root as a member of the base class, the insert function doesn't need to be static and doesn't need to take &root as input. And since a CRTP base class is already correctly templated to have access to the Node type, the base class insert method wouldn't need to be a template. All that would be a lot more things to learn (by looking at some real examples of CRTP) and probably overkill for the code sharing you want.

Would making a binary search tree out of a struct over a class node be bad?

I'm not sure if i should.. or should not use a struct to create a binary search tree, the other option is to create the nodes out of a separate node class. with a data, left and right. Which one is better? And why?
heres my code for the BST
template <typename T>
class BST : public SearchableADT<T>
{
public:
BST(void){ head = NULL; numnodes = 0; }
virtual ~BST(void);
virtual int loadFromFile(string filename);
virtual void clear(void);
virtual void insertEntry(T info);
virtual void deleteEntry(T info);
virtual bool isThere(T info);
virtual int numEntries(void);
//needed for comparison to AVL
int BST<T>::height(t_node* tPTR);
protected:
struct t_node
{
string data;
t_node *L;
t_node *R;
};
int numnodes;
t_node* head;
t_node* cPTR; //current pointer
t_node* pPTR; //parent pointer
t_node* tPTR; //temporary pointer
}; // end of class BST
I'm not sure if you understand the difference between struct and class but basically:
struct
Has public access for all of its members by default and
class
Has private access for all of its members by default.
You can achieve the same thing with both of them but many programmers, including myself, tend to use structs for POD objects (Plain Old Data) for straight up access (It makes it easier to write less).
That said, I think you should put your Node class outside in a different file since the BST and Node classes are very different. Since you gave your BST class a template, I am assuming that you are gonna use more than just the Node class, which gives more reason to separate the files for the projects that you might not use the Node class. If you aren't going to use more than just a Node class, you might consider removing the template and defining the Node struct/class inside the BST class!
It is better to create two classes, one for the BST and another for the node. They are two different abstractions. A node is a simpler abstraction whose main purpose is to hold the data necessary to define a BST. A BST is a higher level abstraction. It's a collection class with its own constraints and expectations.

C++ nested class error "cannot convert ... in assignment"

I'm new to C++ and I keep getting this error message in the following class:
class LinkedList {
class Node *head;
class Node {
Student *student;
Node *next;
Node *prev;
public:
Node(Student *n_student, Node *n_next, Node *n_prev);
~Node();
Student *getStudent() const;
Node *getNext() const;
Node *getPrev() const;
};
public:
LinkedList();
~LinkedList();
void printList();
};
The method that causes the error:
void LinkedList::printList() {
using namespace std;
class Node *p_n;
p_n = head; // ERROR!
while (p_n) {
cout << '[' << (*(*p_n).getStudent()).getId() << ']' << endl;
p_n = (*p_n).getNext();
}
}
The error message I'm getting is
error: cannot convert 'Node*' to
'LinkedList::Node*' in assignment
I've tried casting Node to LinkedList::Node but I keep getting the same message. I'm compiling it in Xcode, not sure if that causes the problem.
Any idea how to fix this?
Change this:
class Node *head;
Into this:
Node *head;
When you declare a field of a certain class inside a class, you don't need the class keyword. Just the type name and its corresponding identifier. Like this:
Node *n;
LinkedList *l;
No class keyword. class keyword is only used when you actually declare/define a class.

Null Object Pattern, Recursive Class, and Forward Declarations

I'm interested in doing something like the following to adhere to a Null Object design pattern and to avoid prolific NULL tests:
class Node;
Node* NullNode;
class Node {
public:
Node(Node *l=NullNode, Node *r=NullNode) : left(l), right(r) {};
private:
Node *left, *right;
};
NullNode = new Node();
Of course, as written, NullNode has different memory locations before and after the Node class declaration. You could do this without the forward declaration, if you didn't want to have default arguments (i.e., remove Node *r=NullNode).
Another option would use some inheritence: make a parent class (Node) with two children (NullNode and FullNode). Then the node example above would be the code for FullNode and the NullNode in the code above would be of type NullNode inheriting from Node. I hate solving simple problems by appeals to inheritence.
So, the question is: how do you apply Null Object patterns to recursive data structures (classes) with default arguments (which are instances of that same class!) in C++?
Use extern:
extern Node* NullNode;
...
Node* NullNode = new Node();
Better yet, make it a static member:
class Node {
public:
static Node* Null;
Node(Node *l=Null, Node *r=Null) : left(l), right(r) {};
private:
Node *left, *right;
};
Node* Node::Null = new Node();
That said, in both existing code, and amendments above, you leak an instance of Node. You could use auto_ptr, but that would be dangerous because of uncertain order of destruction of globals and statics (a destructor of some global may need Node::Null, and it may or may not be already gone by then).
I've actually implemented a recursive tree (for JSON, etc.) doing something like this. Basically, your base class becomes the "NULL" implementation, and its interface is the union of all interfaces for the derived. You then have derived classes that implement the pieces- "DataNode" implements data getters and setters, etc.
That way, you can program to the base class interface and save yourself A LOT of pain. You set up the base implementation to do all the boilerplate logic for you, e.g.
class Node {
public:
Node() {}
virtual ~Node() {}
virtual string OutputAsINI() const { return ""; }
};
class DataNode {
private:
string myName;
string myData;
public:
DataNode(const string& name, const string& val);
~DataNode() {}
string OutputAsINI() const { string out = myName + " = " + myData; return out; }
};
This way I don't have to test anything- I just blindly call "OutputAsINI()". Similar logic for your whole interface will make most of the null tests go away.
Invert the hierarchy. Put the null node at the base:
class Node {
public:
Node() {}
virtual void visit() const {}
};
Then specialize as needed:
template<typename T>
class DataNode : public Node {
public:
DataNode(T x, const Node* l=&Null, const Node* r=&Null)
: left(l), right(r), data(x) {}
virtual void visit() const {
left->visit();
std::cout << data << std::endl;
right->visit();
}
private:
const Node *left, *right;
T data;
static const Node Null;
};
template<typename T>
const Node DataNode<T>::Null = Node();
Sample usage:
int main()
{
DataNode<char> a('A', new DataNode<char>('B'),
new DataNode<char>('C'));
a.visit();
return 0;
}
Output:
$ ./node
B
A
C