can i restrict behaviour of polymorphism? - c++

So i'm trying to implement a binary search tree and avl tree. Each of these classes using different but similar types of nodes. The classes for nodes look like this:
class node
{
protected:
int key;
node* parent, * left, * right;
public:
node(int key, node* parent = nullptr) :key(key), parent(parent), left(nullptr), right(nullptr) {}
~node() {}
};
class avl_node : public node
{
private:
int height;
public:
avl_node(int key, int height, avl_node* parent = nullptr) :node(key, parent), height(height) {}
~avl_node() {}
};
This mostly works. Any node can have connexions with any other node, and any avl_node with any other avl_node. The issue that I think of is that a node could technically have a parent or children avl_node because of polymorphism, and I wouldn't want that to happen. Although I can avoid that by being careful, i wouldn't want it to be possible at all. Is there a way?
p.s. I want to keep the classes related

If it's enough, you could explicitly delete the version of constructor that would take an avl_node*
class node
{
protected:
int key;
node* parent, * left, * right;
public:
node(int key, node* parent = nullptr) :key(key), parent(parent), left(nullptr), right(nullptr) {}
node(int, avl_node*) = delete;
~node() {}
};
Of course, this solution is not foolproof. If you brought an avl_node hidden behind a node pointer, the compiler wouldn't be able to tell (and since polymorphism is mainly dynamic, you would only be protected in this specific case where you attempt to assign the pointer directly)
This would compile.
avl_node myavl;
node n(0, static_cast<node*>(&myavl));
You could try dynamic-casting in the node constructor to tell if it's an avl_node being passed (your nodes would need a vtable for that), but that would make it impossible to call the constructor like that from the avl_node constructor.
Another option would be making a separate constructor intended specifically for the subclass
class node
{
protected:
int key;
node* parent, * left, * right;
node(int key, avl_node* parent) : key(key), parent(parent), left(nullptr), right(nullptr) {}
public:
node(int key, node* parent = nullptr) :key(key), parent(parent), left(nullptr), right(nullptr) { /* do something to not allow avl_node* to be passed */ }
~node() {}
};

You can get rid of polymorphism and avoid code duplication by using a class template for the base, and members that depend on the template argument.
Example:
template<typename T>
class node
{
protected:
int key;
node* parent, * left, * right; // Note: these are actually 'node<T>'.
public:
node(int key, node* parent = nullptr)
: key(key), parent(parent), left(nullptr), right(nullptr) {}
void set_parent(node* p) { parent = p; }
};
class avl_node : public node<avl_node>
{
private:
int height;
public:
avl_node(int key, int height, avl_node* parent = nullptr)
: node(key, parent), height(height) {}
};
class silly_node : public node<silly_node>
{
public:
silly_node() : node(0) {}
};
int main()
{
// Fine
avl_node an(0, 1);
// Fine
avl_node bn(0, 1, &an);
// Also fine
bn.set_parent(&an);
// Fine
silly_node sn;
// Compilation error
avl_node cn(0, 1, &sn);
// Also compilation error
bn.set_parent(&sn);
}

Related

Problem about Initializing inner class Instance

class ListNode;
class LinkedList {
private:
ListNode* start;
class ListNode {
private:
int data;
ListNode* next;
public:
ListNode() : data(-1), next(NULL) {}
ListNode(int data, ListNode* next=NULL) : data(data), next(next) {}
};
public:
LinkedList() : start(NULL) {}
LinkedList(int data) : start(new ListNode(data)) {}
};
there is a error in LinkedList(int data) : start(new ListNode(data)) {}.
It says "you cannot innitialize LinkedList* value using LinkedList::ListNode construction".
Whats is the exact problem means and solutions???
The forward declaration of class ListNode; is not the same thing as class LinkedList::ListNode defined later.
When the compiler finds ListNode* start;, LinkedList::ListNode is unknown, so the compiler uses the ListNode forward declaration. By the time the compiler gets to start(new ListNode(data)), LinkedList::ListNode is known and has a closer scope so it is used instead of ListNode.
Result: start, a ListNode * is pointed at a LinkedList::ListNode. The types clash and the compiler rejects the code.
The simplest solution is to remove the forward declaration of ListNode, since it's likely just an attempt a to fix an earlier undeclared identifier error and will never be defined, and move ListNode* start; to after the definition of LinkedList::ListNode so that there is no ambiguity.
You cannot forward declare an inner class outside the containing class. So, try declaring it first, and then declaring a pointer to it:
class LinkedList {
private:
class ListNode {
private:
int data;
ListNode* next;
public:
ListNode() : data(-1), next(NULL) {}
ListNode(int data, ListNode* next=NULL) : data(data), next(next) {}
};
ListNode* start;
public:
LinkedList() : start(NULL) {}
LinkedList(int data) : start(new ListNode(data)) {}
};

proxy class constructor access

I have some troubles with a c++ project i started. I am trying to implement basic linked list and my attempt includes proxy class in the list class for representing single node. One of the list constructors can get single parameter and initialize the first node of the list with it, but i can't pass that parameter to the proxy class' constructor. Any suggestions how to do it?
Here is some c++ code
template <class TYPE>
class list{
private:
//Proxy class for node representation
class node{
private:
node* next;
TYPE data;
public:
explicit node() : next(nullptr) {}
node (const TYPE& init) : data(init) {}
inline node*& get_next(){
return next;
}
inline TYPE& get_data(){
return data;
}
};
node* head;
unsigned int size;
public:
explicit list() : head(nullptr), size(0) {}
list(const TYPE& init) : list::node(init) {}
Well, you should refer to the instance of node rather than to the class itself. Also, keep in mind that head is a pointer in your example.
Try something like this:
list(const TYPE &init) : head(new node(init)) {}

C++ Updating a variable in object of derived class via pointer

I am building a linked list, where nodes are all linked to Head. The Head is derived from node, but the Head requires a pointer to last node. See the comment at the top of code.
/* Base <= node <= node <= node
* | ^
* | ptr to last node |
* -------------------------
*/
class Node {
private:
Node* prev;
public:
explicit Node(Node* parent) : prev(parent) {
Node* foo_ptr = this;
while (foo_ptr->prev != 0) {
foo_ptr = foo_ptr->prev;
}
// foo_ptr points to Base, how can I now change Base::last?
}
};
class Base : public Node {
private:
Node* last;
public:
Base() : Node(0), last(this) {}
};
How can I change change variable Base::last when adding new node, for example:
Node* n = new Base;
new Node(n); // can Node constructor update n->last?
I was thinking to use virtual function to update the variable, but according to this post: Calling virtual functions inside constructors, its a no no so I do not want to do it. So is there a good way of achieving this type of linked list?
Thanks...
http://coliru.stacked-crooked.com/a/213596aa1ffe7602
I added a flag value so we can tell that we actually accessed the Base class:
#include <iostream>
class Node {
private:
Node* prev;
public:
inline void changeBaseLast(Node* base);
explicit Node(Node* parent) : prev(parent) {
Node* foo_ptr = this;
while (foo_ptr->prev != 0) {
foo_ptr = foo_ptr->prev;
}
// foo_ptr points to Base
// now change Base::last
changeBaseLast(foo_ptr);
}
int data;
};
class Base : public Node {
private:
Node* last;
public:
int flag;
Base() : Node(0), last(this), flag(0) {}
};
//Here, we can see that we change the base_ptr to 1.
void Node::changeBaseLast(Node* base) {
Base* base_ptr = static_cast<Base*>(base);
base_ptr->flag=1;
}
int main() {
Node* n = new Base;
new Node(n);
std::cout << static_cast<Base*>(n)->flag << std::endl;
}
If you pull out the part that refers to the derived class and then inline it, there should be no problems with this. Notice, though, that I need to define the functions that refer to the derived class after I define the derived class.
If you're sure that the last node will always be a Base object, then using static_cast<Base*> may not be that bad.
class Base : public Node {
...
// Factory method to create child nodes
Node* getNode(Node* parent) {
Node* newNode = new Node(parent);
last = newNode;
return newNode;
}
}
This one should be even easier to understand and still uses static_cast, for you want to append by means of the Base class.
class Node {
private:
Node* prev;
public:
explicit Node() : prev{nullptr} { }
void setParent(Node *parent) {
prev = parent;
}
};
class Base : public Node {
private:
Node* last;
public:
Base() : Node{}, last{this} { }
void append(Node *node) {
node->setParent(last);
last = node;
}
};
int main() {
Node* n = new Base;
static_cast<Base*>(n)->append(new Node{});
}
Anyway, I don't understand the need of the Base class.
Can't you simply store somewhere (as an example a struct) two pointers, one for the head of the list and one for the last node?

Suggestions on C++ Inheritence

I have been implementing the Red Black Trees in C++ using inheritence. I have 4 Classes, Node, Tree, RBNode, RBTree.
class Node
{
protected:
int data;
Node *left;
Node *right;
Node *parent;
public:
Node();
Node(int data);
void print_node(ofstream &file);
Node * find_node(int data);
void insert_node(Tree *t);
void left_rotate_node(Tree *t);
void right_rotate_node(Tree *t);
void delete_node(Tree *t);
}
class Tree
{
protected:
Node * root;
list<int> treedata;
public:
Tree();
virtual Node * get_root();
virtual void set_root(Node *root_node);
void insert_into_tree();
void delete_from_tree();
virtual void print_tree();
}
RBNode and RBTree inherit Node, Tree respectively. But I am not able to use the functions of the Node class. For example, the function void Tree::insert_node(Tree *t);
Even in the class RBNode, this function does the same work except that the funntion receives RBTree as the parameter. How can I make use of the same function without redeclaring it in RBNode. I thought of using casting inside function, but how will I know which classes object is calling the function.
Please give me some suggestions. I am new to C++.
Either the inheritance was not properly defined, or there is a confuson on insert_node(Tree *t) which is defined in the Node and not in the Tree.
Anyway, the following minimal code example compiles well:
class Tree;
class Node
{
protected:
int data;
Node *left,*right, *parent;
public:
Node(int data=0) : data(data), left(nullptr), right(nullptr), parent(nullptr) {}
void insert_node(Tree *t) { cout << "Insert" << endl; }
};
class Tree
{
protected:
Node * root;
list<int> treedata;
public:
Tree() : root(nullptr) {}
};
class RBSnode : public Node {}; // public inheritance
class RBStree : public Tree {};
...
RBSnode n;
RBStree t;
n.insert_node(&t);
Note that in absence of the public inheritance specifier, private inheritance is assumed: within the class you have acces to all the protected and public members of the base class, but outside, the class, you don't see the inherited members. I guess it's what happenned to you.

Holding a generic type's instance - C++

I have a tree_node class and a tree class.
template<typename T>
class tree_node
{
public:
tree_node(const std::string& key_, const T& value_)
: key(key_), value(value_)
{
}
private:
T value;
std::string key;
};
template<typename T>
class tree
{
public:
tree() : root(new tree_node<T>("", ???)) { }
private:
tree_node<T>* root;
};
tree_node expects an instance of T when creating. How can I pass it in the ??? place? I can say T(), but it will work only if T has a parameterless constructor. I can't have a parameterless constructor for tree_node as it won't compile if T doesn't have a parameterless constructor.
I am looking for a way to design tree_node which can hold all types correctly including pointer types.
Edit
After trying various methods, I found that boost::optional is helpful in this case. I can make the T value into boost::optional<T> value. This will solve the empty constructor issue. So I can have another constructor overload of tree_node which just takes a key. This can be used by the root node. Is this the correct way to go?
Thanks..
Init root value should be zero. If you push new node you obviously know value.
template<typename T>
class tree
{
public:
tree() : root(0) { }
void push (const std::string& key, const T & t) {
if (root == 0) {
root = new tree_node<T>(key, t);
} else {
// Make complex tree
}
}
private:
tree_node<T>* root;
};
Add
If you use suffix tree you should make two types of vertices:
enum NodeType { EMPTY_NODE, VALUE_NODE };
class base_tree_node
{
public:
base_tree_node() :parent(0), left(0), right(0) {}
virtual NodeType gettype() = 0;
protected:
base_tree_node* parent;
base_tree_node* left;
base_tree_node* right;
};
class empty_tree_node : base_tree_node
{
virtual NodeType gettype() { return EMPTY_NODE; }
}
template<typename T>
class tree_node : base_tree_node
{
public:
tree_node(const std::string& key_, const T& value_)
: key(key_), value(value_)
{
}
virtual NodeType gettype() { return VALUE_NODE; }
private:
T value;
std::string key;
};
tree( const T & t ) : root(new tree_node<T>("", t )) { }
I have once done a linked list (just for fun) which needed a sentinel node not meant to hold any data, and I had the following structure:
struct BaseNode
{
BaseNode* next;
BaseNode(BaseNode* next): next(next) {}
};
template <class T>
struct Node: public BaseNode
{
T data;
Node(const T& data, BaseNode* next): BaseNode(next), data(data) {}
};
template <class T>
struct List
{
BaseNode* head;
List(): head(new BaseNode(0)) {}
void add(const T& value)
{
Node<T>* new_node = new Node<T>(value, head->next);
head->next = new_node;
}
T& get_first()
{
assert(head->next);
return static_cast<Node<T>*>(head->next)->data;
}
//...
};
The class itself must make sure it gets necessary casts right and doesn't try to cast head or root itself to Node<T>.
A tree node should have (or be) a collection of child nodes. A tree should have (or be) a collection of root nodes. Both those collections should be the same type. Very simply:
template <class T>
class NodeCollection
{
std::vector<Node<T> *> nodes;
public:
// any operations on collection of nodes
// copy ctor and destructor a must!
};
template <class T>
class Node : public NodeCollection<T>
{
T value;
public:
// ctor
// access to value
};
template <class T>
class Tree : public NodeCollection<T>
{
public:
// ctor
};
This way the shared definition of Tree and Node is actually in NodeCollection, and so Tree doesn't need to carry a dummy value.