Derived class constructor calling base class constructor - c++

My question is whether or not it's ok call the base class constructor as being initialized to nullptr the way I have below in derivedClassA. The code works as expected but it still feels wrong.
For the sake of length I have omitted other classes that are derived from class Tree , but the idea here is that you can create a Tree object that has any number of derived classes, and call getStringExpression() and it will return whatever getStringExpression evaluates to. For example, if an object of type Tree contains a pointer to an object of DerivedClassA, which has right and left children equal to "Car" and "Ride" then Tree.getStringExpression(); would return "(Car + Ride)". Assume the values Car and Ride are returned by concrete classes derived from Tree that return the string "Car" and "Ride" respectively when their getStringExpression() method is called (and they have no children).
It feels wrong to initialize the base class constructor to nullptr the way I have in derivedClassA because if I create a single object of derivedClassA, then this object is the root node with its two children created during its construction. What happens to the constructed Tree in this scenario? Since it's pointer is nullptr it's not really being used or it's sort of disconnected or univolved with the object of derivedClassA...
I apologize in advance because I know this isn't the most straightforward question.
Tree.h-
class Tree
{
public:
explicit Tree(Tree *rootNode);
virtual ~Tree() {};
virtual std::string getStringExpression() const;
private:
Tree *rootNodePtr = nullptr;
};
Tree.cpp-
#include "Tree.h"
Tree::Tree(Tree *rootNode)
{
rootNodePtr = rootNode;
}
std::string Tree::getStringExpression() const
{
if(rootNodePtr != nullptr)
{
return rootNodePtr->getStringExpression();
}
return "Tree has no children";
}
derivedClassA.h-
#include "Tree.h"
class derivedClassA :
public Tree
{
public:
derivedClassA(Tree *leftChild, Tree *rightChild);
virtual ~derivedClassA();
virtual std::string getStringExpression() const override;
private:
Tree *leftChildPtr = nullptr;
Tree *rightChildPtr = nullptr;
};
derivedClassA.cpp-
#include "derivedClassA.h"
derivedClassA::derivedClassA(Tree *leftChild, Tree *rightChild): Tree(nullptr)
{
leftChildPtr = leftChild;
rightChildPtr = rightChild;
}
derivedClassA::~derivedClassA()
{
}
std::string derivedClassA::getStringExpression() const
{
auto expressionValue = "(" + leftChildPtr->getStringExpression() + "+" + rightChildPtr->getStringExpression() + ")";
return expressionValue;
}

It sounds like you have merged the classes of Tree and Node. You are initializing Tree in the constructor with a single "root" tree, when it should have a "root Node that itself has two children. In that case, Node wouldn't inherit from Tree - you would have two separate classes.
Or perhaps you have an abstract Node class and a BinaryNode that inherits it to represnet a node with two children, opening up the door for different node types (nodes with more than two children, or unbalanced children).
So to answer your question, yes it seems odd that you are initializing the "base" with a default value, but I think it's because your class hierarchy is wrong. Meaning derivedClassA is not a Tree.

Related

Creating a class with attributes of this class type + inheritance to other class (Node classs and NodeAVL)

I'm trying to do the following code:
class Node
{
protected:
int *value;
Node *leftChild;
Node *rightChild;
friend class BST;
public:
Node(int value = 0);
virtual ~Node();
virtual int info();
};
Node::Node(int value) : leftChild(nullptr), rightChild(nullptr) {
this->value = new int(value);
std::cout << "Creating the node " << *(this->value) << "\n";
}
class NodeAVL : public Node
{
private:
friend class AVL;
public:
int *balanceFactor;
NodeAVL(int value = 0);
virtual ~NodeAVL();
};
NodeAVL::NodeAVL(int value) : Node(value) {
this->balanceFactor = new int(0);
std::cout << "Creating the AVL node " << *(this->value) << " with balance factor " << *(this->balanceFactor) << "\n";
}
Now, my problem is that I should derive NodeAVL (mandatory), and I have a problem with the Node class (base class), because there are declarations of Node *leftChild and Node *rightChild, and when I create an AVL node, it creates its children of type Node*. How can I create it with the type NodeAVL*?
Or how can I create a class T like:
class T{
T* leftChild;
T* rightChild;
}
so that I would have Node class have Node children and NodeAVL which is derived from Node have NodeAVL children?
Since you have tagged your post with polymorphism I will give you a runtime polymorphism based answer. You don't.
Part of the point of runtime polymorphism is that an object dervied from the base class can be passed and stored as an object of the base class while still retaining its overriden functionality (Yes slicing is an issue but we are dealing with pointers here). Therefore you do not need Node to be changed to NodeAVL, simply setting leftChild or rightChild to point at an object of NodeAVL instead of Node is enough, any overriden methods will call the method in NodeAVL.
You are setting your nodes to nullptr anyway but if you didn't then you could make a Node contructor which takes pointers for leftChild and rightChild (possibly make it protected so only derived classes can use it).
As a side note use your initaliser list to set value instead of setting it afterwards. Also prefer smart pointers to naked pointers.

Getters in recursive class with pointers to other instances of the class

For a school project, I need to build a BinarySearchTree for a tuple of index and value of type T and I decided to make it using left and right child pointers (to other instances but bear with me).
To make the class a bit more realistic and readable, I built 3 different classes: Tree, BinaryTree, and BinarySearchTree with inheritance.
I declared the getter and the setter of the left and right children in the BinaryTree class and the class looks like this:
template <typename T>
class ArbreBinaire : public Arbre<T>
{
private:
ArbreBinaire<T>* _leftChild;
ArbreBinaire<T>* _rightChild;
public:
ArbreBinaire(lu index = 0, T element = T(0), ArbreBinaire<T>* lchild = nullptr, ArbreBinaire<T>* rchild = nullptr) :
Arbre<T>(index, element), _leftChild(lchild), _rightChild(rchild) {};
virtual ArbreBinaire<T>* getLC() const { return _leftChild; }
virtual ArbreBinaire<T>* getRC() const { return _rightChild;}
void setLC(ArbreBinaire<T>* lc) { _leftChild = lc; lc->setParent(this); }
void setRC(ArbreBinaire<T>* rc) { _rightChild = rc; rc->setParent(this); }
virtual ~ArbreBinaire() = default;
};
And in my BinarySearchTree, in a few places I need to go through my tree (to insert or search for exemple).
So here comes finally my question: What is the best way to get the left child of my object, which is of type BinarySearchTree and to keep the continuity (BST that has BST left child and BST right child)
I thought of multiple options:
virtual getter and setter and redefining it in every derived class but there are 2 other "problems" with that solution.
Should I have 2 other members in my BST, which would be of type BST* and basically point to the same object than the ones in my BinaryTree ?
Should I just redefine my getters to return a dynamic_cast version like this : BST<T>* getLC() { return dynamic_cast<BST<T>*> (this->BinaryTree::getLC()) } ?
Putting all my members, getters and setters in my BST class (but that goes opposite to the definition of a BinaryTree, the base class : a BinaryTree with no children is not a BinaryTree)
3.Just casting every time i need to get my left or right child
4.Casting everytime i need to use a method in BST (derived class) ?
5. Any other suggestions?

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.

Remove dynamic_cast in derived class of tree node

I have a class which is a node of a tree, called Node. I need to create a DerivedNode class type which has some extra functionality. The problem is that Node has a vector of Node* as a member variable, so when DerivedNode inherits from Node, it inherits this vector. I've created a basic example showing the issue:
#include <iostream>
#include <vector>
class Node {
public:
Node(int value_) : value(value_) {}
int foo() { return value; }
virtual void add(Node* new_node) {
children.push_back(new_node);
}
protected:
std::vector<Node*> children;
int value;
};
class DerivedNode : public Node {
public:
DerivedNode(int value_) : Node(value_) {}
int bar() { return value*2; }
// Ensures we only add children of type DynamicNode*
virtual void add(DerivedNode* new_node) {
children.push_back(new_node);
}
void print() {
for (size_t i = 0; i < children.size(); ++i) {
std::cout << dynamic_cast<DerivedNode*>(children[i])->bar() << std::endl;
}
}
};
int main() {
DerivedNode* child_a = new DerivedNode(5);
DerivedNode* child_b = new DerivedNode(6);
DerivedNode parent(1);
parent.add(child_a);
parent.add(child_b);
parent.print();
delete child_a;
delete child_b;
}
My question is, how can I do this without the dynamic_cast? My actual code is far more complex which means that there are dynamic casts everywhere.
First add function in derived class is totally useless, it does not override add function from base class, it overloads it. In such way you still can add Node*'s to the derived class. To prevent this you should override add(Node*) as private.
If you does not like dynamic cast, you may use static cast instead
or
You may have virtual bar in base class that does not do anything
or
you can cast the vector itself (the whole thing) and assign to reference or pointer to std::vector DerivedNode*
You can't have it both ways. You either have IS-A principle reflected in the design of your classess, or you don't. If DerivedNode is Node, than the vector of Nodes should be indistinguishable from vector of DerivedNodes - and no casts are neccessary. If this can not be achieved, that you simply can not use vector of base pointers.
Any dynamic_cast in production code for me is a hard block for any review, as it clearly violates the basic design principles.

One class requires another and that other class requires the first one. How do I do that?

Here we have two classes, let's call it Tree and Fruit. A Tree can only have one or no Fruits at any given time. A Fruit can only be on one Tree. From the Tree object, you can get its Fruit by the function getTreeFruit( ). From the Fruit object, you can get its "owner" by the function getFruitOwner( ) which returns a Tree object.
Now in the Tree header, we have this:
#include "Fruit.h"
class Tree {
private:
Fruit m_Fruit; // The fruit in the tree.
public:
Tree ( Fruit tree_fruit );
Fruit getTreeFruit( ); // Returns m_Fruit.
}
And on the Fruit header:
#include "Tree.h"
class Fruit {
private:
Tree m_Owner; // The Tree object that "owns" the fruit.
public:
Fruit ( Tree fruit_owner );
Tree getFruitOwner( ); // Returns m_Owner.
}
I realized that Tree and Fruit include each other's header files and this causes an error. How do I go about fixing the error?
Thanks a lot in advanced. :)
You should be storing references to the Tree in the Fruit objects, not the tree itself.
References are a better choice than pointers here, because they express the condition that fruit can't magically hop from one tree to another. A reference can only be set when an object is constructed, so you have to use an initializer list in the constructor.
Then, you can use a forward declaration of Tree.
class Tree;
class Fruit {
private:
Tree &owner; // The Tree object that "owns" the fruit.
public:
Fruit (Tree &fruit_owner ) : owner(fruit_owner)
{ ... };
Tree &getFruitOwner( ); // Returns owner.
I realized that Tree and Fruit include each other's header files and this causes an error.
This is not the only problem. Basically you want two objects to contain each other recursively, which is not possible.
What you probably want is to make fruit have a pointer to the tree it belongs to, and forward-declare Tree in Fruit.h like so:
Tree.h:
#include "Fruit.h"
class Tree
{
private:
Fruit m_Fruit; // The fruit in the tree.
public:
Tree (Fruit tree_fruit);
Fruit getTreeFruit(); // Returns m_Fruit.
}
Fruit.h
class Tree;
class Fruit
{
private:
Tree* m_Owner; // The Tree object that "owns" the fruit.
public:
Fruit(Tree* fruit_owner);
Tree* getFruitOwner(); // Returns m_Owner.
}
use forward declaration of the class and make the tree as pointer
class Tree;
class Fruit {
private:
Tree *m_pOwner; // The Tree object that "owns" the fruit.
public:
Fruit ( Tree *fruit_owner );
Tree* getFruitOwner( ); // Returns m_Owner.
}
You should use forward declaration:
class Tree;
class Fruit {
private:
Tree *m_Owner; // The Tree object that "owns" the fruit.
public:
Fruit ( Tree *fruit_owner );
Tree *getFruitOwner( ); // Returns m_Owner.
}