Overriding a structure defined in a base class from a derived class
I have created a class (named BST) for a binary search tree in C ++ and am now trying to create a class (named AVL) for AVL trees that inherits from the BST class. I have defined a struct (called a node) inside my BST class and would now like to add extra member height to it when used in an AVL derived class. I cannot find a way to override the struct and add an extra member to it only when it is used for an AVL class. Here is my code for the BST class:
class BST
{
protected:
struct node
{
int val;
node* left;
node* right;
};
node* root;
public:
BST()
{
this->root = NULL;
}
void insert(int val);
void display();
void displayPretty();
void displaySorted();
int min();
int max();
int height();
void remove(int val);
int after(int val);
int before(int val);
static bool isBST(BST tree);
~BST()
{
removeAll(this->root);
}
protected:
node* create(int val);
node* insertInto(node* root,int val);
void displayLevelOrder(queue<node*>* q);
void displayPretty(node* p, int indent);
void displayInorder(node* root);
node* getMin(node* root);
node* getMax(node* root);
int heightOf(node* root);
node* removeFrom(node* root,int val);
void removeAll(node* root);
node* getSuccessorOf(int val,node* root,node* prev);
node* getPredecessorOf(int val,node* root,node* next);
static bool isBST(node* root,int min,int max);
};
And my incomplete code for the AVL class:
class AVL : public BST
{
protected:
struct node
{
// redefine node here (by adding the 'height' member)
// such that all the node variables/pointers in BST (e.g. root)
// also get created with this new definition
};
public:
AVL() : BST(){}
void insert(int val);
void remove(int val);
private:
node* insertInto(node* root,int val);
node* removeFrom(node* root,int val)
};
I've tried using struct inheritance like this:
struct avlnode : node
{
int height;
};
But the problem here avlnode->left
and avlnode->right
is it is type node*
instead of type avlnode*
and so I cannot access the height element from them.
Any help would be greatly appreciated: D
source to share
In the OP, the derived class was named AVLTree
. Unfortunately the OP is not an MCVE . "Fascinating" implementation details are not considered (or even not yet developed). After remembering how the AVL tree works , I decided to just ignore it. Thus, I just want to show how the classes could be obtained:
Note. I have split the example code to prevent nested scroll boxes.
Source trees.cc
:
First, some headers of the standard library I want to use:
#include <iostream>
#include <iomanip>
#include <string>
Base class declaration BTree
:
class BTree {
starting with the built-in class for nodes:
// types:
protected:
struct Node {
int value;
Node *pLeft, *pRight;
// constructor.
Node(int value): value(value), pLeft(nullptr), pRight(nullptr) { }
// destructor.
virtual ~Node() { delete pLeft; delete pRight; }
// disabled:
Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
// prints node.
virtual void print(std::ostream &out)
{
out << "Node " << value;
}
};
... variables ...
// variables:
protected:
Node *_pRoot;
... and methods.
// methods:
public:
// constructor.
BTree(): _pRoot(nullptr) { }
// destructor.
~BTree() { delete _pRoot; }
// disabled:
BTree(const BTree&) = delete;
BTree& operator=(const BTree&) = delete;
// inserts a node.
bool insert(int value) { return insert(_pRoot, value); }
// prints the tree.
void print(std::ostream &out, bool inOrder)
{
if (_pRoot) {
if (inOrder) printInfix(out, _pRoot, 0);
else print(out, _pRoot, 0);
} else out << "EMPTY." << std::endl;
}
// internal methods:
protected:
// creates and inserts a node.
bool insert(Node *&pNode, int value);
// prints a sub-tree.
void print(std::ostream &out, Node *pNode, int indent);
// prints a sub-tree in order.
void printInfix(std::ostream &out, Node *pNode, int indent);
};
Implementation of internal methods:
bool BTree::insert(Node *&pNode, int value)
{
if (!pNode) {
pNode = new Node(value);
return true;
}
if (value == pNode->value) return false; // ERROR!
return insert(
value < pNode->value ? pNode->pLeft : pNode->pRight, value);
}
void BTree::print(std::ostream &out, Node *pNode, int indent)
{
out << std::setw(indent) << "";
pNode->print(out);
out << std::endl;
indent += 2;
if (pNode->pLeft) print(out, pNode->pLeft, indent);
if (pNode->pRight) print(out, pNode->pRight, indent);
}
void BTree::printInfix(std::ostream &out, Node *pNode, int indent)
{
if (pNode->pLeft) printInfix(out, pNode->pLeft, indent + 2);
out << std::setw(indent) << "";
pNode->print(out);
out << std::endl;
if (pNode->pRight) printInfix(out, pNode->pRight, indent + 2);
}
Derived class for 2 nd tree :
class BTree2: public BTree {
starting with the built-in class for derived nodes:
// types:
protected:
struct Node: public BTree::Node {
int height;
// constructor.
Node(int value, int height):
BTree::Node(value), height(height)
{ }
virtual ~Node() = default;
// disabled:
Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
// prints node.
virtual void print(std::ostream &out)
{
out << "Node " << value << " (height: " << height << ")";
}
};
... no variables, but some derived methods ...
// methods:
public:
// constructor.
BTree2(): BTree() { }
// destructor.
~BTree2() = default;
// disabled:
BTree2(const BTree2&) = delete;
BTree2& operator=(const BTree2&) = delete;
// inserts a node.
bool insert(int value)
{
return insert((Node*&)_pRoot, value, 0);
}
// internal methods:
protected:
// creates and inserts a node.
bool insert(Node *&pNode, int value, int height);
};
... and implementation:
bool BTree2::insert(Node *&pNode, int value, int height)
{
if (!pNode) {
pNode = new Node(value, height);
return true;
}
if (value == pNode->value) return false; // ERROR!
return insert(
(Node*&)(value < pNode->value ? pNode->pLeft : pNode->pRight),
value, pNode->height + 1);
}
Last but not least, with a little test:
// main function
int main()
{
// some test data
int data[] = { 3, 7, 21, 2, 12, 1, 104, 13 };
enum { nData = sizeof data / sizeof data[0] };
// binary tree
{ std::cout << "Binary Tree:" << std::endl;
BTree bTree;
std::cout << "Build..." << std::endl;
for (int value : data) bTree.insert(value);
std::cout << "Print Hierarchy..." << std::endl;
bTree.print(std::cout, false);
std::cout << "Print Sorted..." << std::endl;
bTree.print(std::cout, true);
std::cout << "Destroy..." << std::endl;
std::cout << std::endl;
}
// derived binary tree
{ std::cout << "Derived Binary Tree:" << std::endl;
BTree2 bTree;
std::cout << "Build..." << std::endl;
for (int value : data) bTree.insert(value);
std::cout << "Print Hierarchy..." << std::endl;
bTree.print(std::cout, false);
std::cout << "Print Sorted..." << std::endl;
bTree.print(std::cout, true);
std::cout << "Destroy..." << std::endl;
std::cout << std::endl;
}
// done
return 0;
}
I have uploaded the sample to ideone.com .
I have compiled and tested it with gcc in cygwin on Windows 10:
$ g++ -std=c++11 -o trees trees.cc
$ ./trees.exe
Binary Tree:
Build...
Print Hierarchy...
Node 3
Node 2
Node 1
Node 7
Node 21
Node 12
Node 13
Node 104
Print Sorted...
Node 1
Node 2
Node 3
Node 7
Node 12
Node 13
Node 21
Node 104
Destroy...
Derived Binary Tree:
Build...
Print Hierarchy...
Node 3 (height: 0)
Node 2 (height: 1)
Node 1 (height: 2)
Node 7 (height: 1)
Node 21 (height: 2)
Node 12 (height: 3)
Node 13 (height: 4)
Node 104 (height: 3)
Print Sorted...
Node 1 (height: 2)
Node 2 (height: 1)
Node 3 (height: 0)
Node 7 (height: 1)
Node 12 (height: 3)
Node 13 (height: 4)
Node 21 (height: 2)
Node 104 (height: 3)
Destroy...
$
Notes:
-
Representing virtual methods in
struct Node
allows you to usedynamic_cast<>()
. AFAIK,dynamic_cast<>()
can only be applied to pointer types. So I just did a C-cast (i.e.(Node*&)
), which C ++ purists really don't like. -
insert()
class BTree2
does not use any attachments forclass BTree
. This is to ensure that every node in the tree actually existsBTree2::Node
. -
BTree::print()
does not need to be overloaded due to virtual methodsNode::print()
.
This diagram just shows some ways to reuse code.
Templates are just another possibility. The standard library (like std :: set <> ) gives an example of what it might look like.
source to share
If you are using structure inheritance, the Derived class inherits the struct node as is and you get node * instead of avlnode *.
You can now override the structure of the node in a derived class, which will hide the node in the parent and prefer
Perhaps you can declare a height variable in the node of the parent class and only use it in the derived class, or declare vector<int> heights
in the Derived class and store the heights there.
Also, declare the struct node outside the class and use an instance of it as a member of your classes.
source to share