Super vs Subclass inheritance of a constructor C++ - c++

So this is the base class for a binary search tree with left, right, parent and data.
template<class Data>
class BSTNode
{
public:
/** Constructor. Initialize a BSTNode with the given Data item,
* no parent, and no children.
*/
BSTNode(const Data & d) : data(d)
{
left = right = parent = 0;
}
BSTNode<Data>* left;
BSTNode<Data>* right;
BSTNode<Data>* parent;
Data const data; // the const Data in this node.
/** Return the successor of this BSTNode in a BST, or 0 if none.
** PRECONDITION: this BSTNode is a node in a BST.
** POSTCONDITION: the BST is unchanged.
** RETURNS: the BSTNode that is the successor of this BSTNode,
** or 0 if there is none.
*/
BSTNode<Data>* successor()
{
BSTNode<Data>* cursor;
BSTNode<Data>* par;
cursor = this->right;
par = this->parent;
if (this->right != NULL)
{
while (cursor->left != NULL) {
cursor = cursor->left;
}
return cursor;
}
if ((this->right == NULL) && (this == par->left))
return this->parent;
if ((this->right == NULL) && (this == par->right))
{
do
{
cursor = par;
par = par->parent;
if (par == NULL)
{return cursor;}
} while(cursor != par->left);
return par;
}
if (this->right == NULL && this->parent == NULL)
return NULL;
return NULL;
}
};
The subclass is RSTNode that is supposed to use all the members of BSTNode and add a priority on top of that:
template<class Data>
class RSTNode: public BSTNode<Data>
{
public:
int priority;
RSTNode(Data const & d)
: BSTNode<Data>(d)
{
//call a random number generator to generate a random priority
priority = rand();
}
};
Now the problem is i'm not sure how to implement the constructor for the RSTNode as it does not recognize the members of BSTNode for some reason. I know that it should recognize them as it is supposed to inherit this information. Any help is appriciated.

Ok, I compiled this in Visual Studio...
template<class Data>
class BSTNode
{
public:
/** Constructor. Initialize a BSTNode with the given Data item,
* no parent, and no children.
*/
BSTNode(const Data & d) : data(d)
{
left = right = parent = 0;
}
BSTNode<Data>* left;
BSTNode<Data>* right;
BSTNode<Data>* parent;
Data const data; // the const Data in this node.
};
template<class Data>
class RSTNode : public BSTNode<Data>
{
public:
int priority;
RSTNode(Data const & d)
: priority(rand()),
BSTNode<Data>(d)
{
left = 0; //Accessible because public
right = 0;
parent = 0;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
RSTNode<std::string> node(std::string("test"));
return 0;
}
It compiled so no access issues. Like other posters above it seems to me that you are either not posting the detail of your problem, or you are not understanding something fundemental.
>Now the problem is i'm not sure how to implement the constructor for the RSTNode as it >does not recognize the members of BSTNode for some reason. I know that it should recognize >them as it is supposed to inherit this information. Any help is appriciated.
The code above implements a constructor, or if you wanted to specifically have left, right and parent set then you would need :
BSTNode(const Data & d, BSTNode* l, BSTNode* r, BSTNode* p)
: data(d),
left(l),
right(r),
parent(p)
{
}
and then use it in the RSTNode, or have a similar one for RSTNode that passed through to that one....
RSTNode(Data const & d, BSTNode* l, BSTNode* r, BSTNode* p)
: priority(rand()),
BSTNode<Data>(d,l,r,p)
{
}
Hope that helps a little, note that you should prefer initialiser lists to direct access to members in the ctor. But if you cannot change the base class then you would need to...
Corrected typo - data -> Data

That's because the default scope for data members is private. You need to declare them as protected if you want to access them in a subclass.
Better still, add a constructor to BSTNode that allows you to pass in initialisation values, and call this from the RSTNode constructor, since it should be the base class that is managing the lifetime of its members.

If I've read this correctly your attempting to inherit from a templated class:
class RSTNode: public BSTNode<Data>
Where your class definition of BSTNode isn't a templated class?
class BSTNode {
Is this part of the problem or have you pasted the wrong code?
You could fix it by either templating BSTNode
template <typename T> class BSTNode {
or deriving RSTNode from non-templated BSTNode:
class RSTNode: public BSTNode
However the fact that you've tried to to what you've written implies you aren't really understanding class definitions at a much deeper level, and the fact you are trying to set base class parameters directly in a derived class constructor and that you've made them public would lead me to believe you need to learn more about object oriented design - so although this might solve your problem technically, it's only tip of the iceberg when it comes to the issues you are having.
Also saying "it does not recognize the members of BSTNode for some reason" isn't very helpful as I suspect that isn't the exact output of your compiler when you try to do it.

Related

Alternative to virtual templated function

I currently use a tree structure, made out of subtypes of the class Node. The base Node class looks something like this:
// Base Node Type
class Node
{
public:
virtual ~Node() = default;
virtual std::vector<Node*> GetChildren() const = 0;
};
Here are some example Node subtypes:
// First Node Subtype
class NodeOne : public Node
{
public:
NodeOne(std::unique_ptr<Node>&& t_node)
: m_Node{ std::move(t_node) }
{
}
virtual ~NodeOne() = default;
std::vector<Node*> GetChildren() const override
{
std::vector<Node*> children{};
AddChildren(children, m_Node);
return children;
}
private:
std::unique_ptr<Node> m_Node{};
};
This node owns a pointer to another child Node (can be null).
// Second Node Subtype
class NodeTwo : public Node
{
public:
NodeTwo(std::unique_ptr<NodeOne>&& t_leftNode, std::unique_ptr<NodeOne>&& t_rightNode)
: m_LeftNode{ std::move(t_leftNode) }, m_RightNode{ std::move(t_rightNode) }
{
}
virtual ~NodeTwo() = default;
std::vector<Node*> GetChildren() const override
{
std::vector<Node*> children{};
AddChildren(children, m_LeftNode);
AddChildren(children, m_RightNode);
return children;
}
private:
std::unique_ptr<NodeOne> m_LeftNode{};
std::unique_ptr<NodeOne> m_RightNode{};
};
This node owns a pointer to two child NodeOnes (both can be null). As you can see, both implement the pure virtual function GetChildren(). This is the implementation of the AddChildren() function (it just adds the Node* and its Node* children to the std::vector<Node*>):
// AddChildren() Implementation
template<typename T>
void AddChildren(std::vector<Node*>& t_vec, const std::unique_ptr<T>& t_child)
{
if (!t_child)
return;
auto children{ t_child->GetChildren() };
t_vec.insert(t_vec.end(), children.begin(), children.end());
t_vec.push_back(t_child.get());
}
I recently noticed, getting children of all Node subtypes from GetChildren() is not what I actually want most of the time. I often need children of just one specific interface or type. I wanted to achieve this by making the GetChildren() function a template<>, and then in AddChildren() I would only add a Node* to the std::vector<Node*> if it is of that type (with a constexpr if statement or something similiar). I just found out that template<> on a virtual function is not allowed in C++. Is there any way I could GetChildren() of only one type (I don't want to use RTTI so I would prefer a compile time solution).

how to access class private data members in method parameter of class , i get an error invalid use of non static data members [duplicate]

This question already has answers here:
How to use a member variable as a default argument in C++?
(4 answers)
Closed 2 years ago.
i have two classes Node and AvlTree , i will make other methods of AvlTree later but i can't access root data member of AvlTree in it's own class , how can i access root in AvlTree class inOrder method.
My code is following here
class Node {
public:
int key;
Node* left;
Node* right;
int height;
Node(int key) : key(key) , left(nullptr) , right(nullptr) , height(1) {};
};
class AvlTree {
private:
Node* root;
public:
AvlTree() : root(nullptr) {};
int height(Node* ptr) {
}
int getBalanceFactor(Node* ptr) {
}
void inOrder(Node* itr = root) { // <--- i get an error here
}
};
I tried with this->root but that also does't work , what i am do wrong here , also can i not access like this in it's own class.
I got an error like
09_avl_tree.cpp:36:34: error: invalid use of non-static data member ‘AvlTree::root’
36 | void inOrder(Node* itr = root) {
| ^~~~
09_avl_tree.cpp:15:15: note: declared here
15 | Node* root;
| ^~~~
I don't want to make root as static data member. because i want multiple instances of AvlTree.
The short answer, as the compiler is telling you, is that you can't do that as a default value of an argument.
The simplest approach would be to overload the inOrder() function, for example (within the definition of AvlTree)
void inOrder(Node *itr)
{
// whatever
}
void inOrder()
{
inOrder(root);
}
Also, unrelated to your question, the shadowing of member names in Nodes constructor (e.g. an argument named key used to initialise a member named key) is not a good idea, since it is easy to mislead human readers about what the code does. It is therefore often considered preferable to name the argument differently from the member.

Alternative to template variables?

I'm building a binary search tree. As the generic person I am, I want to allow all types to be able to act as keys to nodes in the tree.
So I came up with the following:
class foo
{
private:
template<class T>
struct node
{
T key;
node* left;
node* right;
};
node<>* _root; //point of interest
public:
//.....
template<class T>
void insert(const T& key);
};
As I insert the nodes into the tree, I can create node objects according to the type of the key, but I don't know how to declare the _root in such a way (when using insert on an empty tree, I can easily pick the type for _root).
I believe C++14's template variables can help me here, but unfortunately MSVC's compiler hasn't implemented that feature yet.
Question: How do I declate _root in the most generic way? How did people do it in the past?
Just storing nodes is not a problem:
class foo
{
struct node
{
virtual ~node() {}
node * left;
node * right;
}
template<typename T>
struct key_node: node
{
T key;
~value_node() {}
}
node *root;
};
The problem will come when you want to access the key value within a node (because you will need to store the type information somehow).
Alternately, you can use boost::any instead of a T template:
class foo
{
struct node
{
boost::any key;
node * left;
node * right;
}
node *root;
};
... and use the interface of boost::any to get the value of they key (but even here you will probably need information on the type stored in any before you can access it in a generic way).

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.

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