I finished writing an AVL tree, and one of the things that bothered me when programming it is deciding which methods belong to which class:
template <class ValueType,class CompareFunction>
class avlTree{
class avlTreeException{};
public:
class ElementDoesntExist : public avlTreeException{};
class EmptyTree : public avlTreeException{};
class ElementAlreadyExists : public avlTreeException{};
private:
class Node{
friend class avlTree;
ValueType* data;
Node *sonA,*sonB,*dad;
int height,balance;
private:
CompareFunction compare;
int treeSize;
Node* root;
};
(I removed the public\private methods to save space).
For some methods I think I made the right choice: update is a method of Node (updates height,etc).
Insert/remove are functions of the tree.
But for example the function destroyNodeTree(Node*) which is used by the tree destructor. What I did is to have destroyNodeList() call destroyNodeTree(root)
template <class ValueType,class CompareFunction>
void avlTree<ValueType,CompareFunction>::avlTree::destroyNodeTree(Node* rooty) {
if(!rooty){
return;
}
Node *A=rooty->sonA,*B = rooty->sonB;
destroyNodeTree(A);
destroyNodeTree(B);
}
However, I could have made destroyNodeTree() a method of Node, and call it on the root from the destructor (it would be implemented in the same way).
I had a similar issue deciding where the method findNode(const ValueType&) should go, meaning it obviously is a public method of tree, but should I create a method for Node with the same name and have the tree function call the node method on the root? Is it even acceptable to have a public function and an inner class method with the same name?
In my opinion it's better to have it as a method of nodes because that gives more flexibility (I'll be able to search for a node only under a certain node), but on the other hand that means that the method either needs to create an instance of class compare, or have each node keep a copy of an instance, or have class compare as a static function. Each of those has a disadvantage in my opinion though: creating an instance can be costly, keeping a copy can be costly, and forcing the user to make the function static doesn't seem right to me (but I'm horribly inexperienced so fix me if I'm wrong).
In any case I eventually made findNode a treeFunction only and not a method (the HW assignment didn't need the tree to able to search from a specific node so it doesn't make any difference there) but I don't want to write bad code.
To conclude, how do we decide where to save performance,memory,flexibility of the user (would he rather be able to search from any node or create nonstatic compare functions?)
Related
I have a tree-like data structure that I've set up like this:
class Root; // forward declaration
class Tree {
public:
void addChildren(Root &r, ...) { childA = r.nodeSpace.allocate(); ... }
// tons of useful recursive functions here
private:
Tree *childA, *childB, *childC;
Tree *parent;
int usefulInt;
};
class Root : public Tree {
friend class Tree; // so it can access our storage
public:
private:
MemoryPool<Tree> nodeSpace;
};
I really like this structure, because
I can call all the recursive functions defined on Tree on Root as well, without having to copy-paste them over.
Root owns the storage, so whenever it passes out of scope, that's how I define the tree as no longer being valid.
But then I realized a problem. Someone might inadvertently call
Tree *root = new Root();
delete root; // memory leak! Tree has no virtual destructor...
This is not an intended usage (any ordinary usage should have Root on the stack). But I am open to alternatives. Right now, to solve this, I have three proposals:
Add virtual destructor to Tree. I would prefer not doing this because of the overhead as the tree can have many, many nodes.
Do not let Root inherit from Tree but instead have it define its own Tree member. Creates a little indirection, not too terrible, can still call the tons of useful recursive functions in Tree by doing root.tree().recursive().
Forbid assignments like Tree *root = new Root();. I have no idea if this is even possible or discouraged or encouraged. Are there compiler constructs?
Something else?
Which one of these should I prefer? Thank you very much!
The root node class (or any other node class) should not be an interface class. Keep it private and then inheritance without dynamic polymorphism (virtual) is not dangerous because the user will never see it.
Forbid assignments like Tree *root = new Root();. I have no idea if this is even possible or discouraged or encouraged. Are there compiler constructs?
This would be done by having Root inherit from Tree as a private base class.
I have begun writing a polymorphic recursive descent parser in C++. However I am running an issue. The classes are set up like this:
class Node {
public:
std::vector<Node*> children;
};
class NodeBinary : public Node {
public:
Node* left;
Node* right;
};
class NodeUnary : public Node {
public:
Node* operand;
};
class NodeVar : public Node {
public:
std::string string;
NodeVar(std::string str) : string(str) {};
};
class NodeNumber : public Node {
public:
signed long number;
NodeNumber(signed long n) : number(n) {};
};
// etc.
And then classes like NodeDeclaration, NodeCall, NodeNot, NodeAssignment, NodePlus, NodeMinus, NodeIf etc. will inherit either from Node or something less generic like NodeBinary or NodeUnary.
However, some of them take more specific operands. NodeAssignment always takes a var and a number/expression. So I will have to override Node* left to NodeVar* left and NodeExpr* right. The problem comes in with things like NodePlus. Left can be a NodeVar or a NodeExpr! And the root node has a similar problem: while parsing at the top level to add children nodes to root, how is it possible to tell if a child is a NodeExpr, a NodePlus, a NodeIf etc...?
I could have all Nodes have a enum "type" that says what type it is, but then whats the point of having a nice polymorphic inheritance tree?
How is is this problem normally solved??
If you're using class inheritance for your AST nodes, you need to create an appropriate inheritance hierarchy, as with any object-oriented design.
So, for example, NodeAssignment (which is presumably a specialization of NodeStatement) needs to contain a NodeLValue (of which a NodeVariable is a specialization) and a NodeValue. As usual, LValues (i.e. things you can assign to) are a subset of Values, so NodeLValue will be a specialization of NodeValue. And so on. Your binary operator node will contain left and right members, both of which are NodeValue base objects (I would expect NodeValue to be pure virtual, with a large number of specific specializations.)
If you insist on using a recursive descent parser, each parsing function needs to return an appropriate subclass of Node, so that the function which parses the left-hand side of an assignment would logically return a NodeLValue*, ready to insert into the NodeAssignment constructor. (Frankly, I'd ditch the word Node in all of those class names. Put them all into the namespace node:: and save yourself some typing.)
I need to implement a custom tree class (using C++). Throughout my work I've seen many tree implementations. Some implemented a "super Node" class which was exposed to the user. An instance of which (root node) acted as the tree. Some exposed a tree class, which utilized a node class to construct a tree. Some used the node class as a pure data struct, leaving functionality such as tree construction to the tree class. Others put the construction - like node.Split(), into the node class.
Say you needed to design a binary tree (like a KD-tree). What would be the "best" approach from OOP perspective. Have node class just contain the data, or the logic to split itself into children? How much logic in general should a node class contain?
Thanks ahead for constructive input!
Here's one OOP rule you should always follow,
Every class represents an entity. Classes have properties and methods
i.e. the attributes of the entities and it's behaviour
So you need to follow your understanding of the scenario.
Here's how I look at a node.
It has some data, a right node reference and a left node reference. I don't think a node should be able to do anything except provide you with the data so I would write a node class something like this:
class Node
{
public:
int Data; // yeah, you would obviously use templates, so it's not restricted to a particular type
Node* Left;
Node* Right;
// also you can write constructors and maybe some sort of cast operator overload to be able to make the
// we could also make it return the subtree itself
getRightSubTree(){ return Tree(*Right); }
getLeftSubTree(){ return Tree(*Left); }
};
A Tree should be like this then.
class Tree
{
private:
Node root;
public:
Tree(Node t):root(t){} // every tree should have a root. Cannot be null.
// since the root node will be able to handle the tree structure, now we'll need the necessary methods
void addNode(Node n){
// code here
}
....
getSubTree(int data){
// check if node with that data exists and all
...
Node n = getNode(data);
return Tree(n);
}
};
Okay so I think you've got an idea now. It's all about how you look at the system.
What should I know about having two separate classes in one .h file?
I have a binary search tree class with all the members and public & private functions.
class BinarySearchTree
{
struct Node {
Node* left;
Node* right;
int val;
};
};
and following that code I want to design a stack of pointers to that binary search tree node. Within the same.h file I have
class stack
{
Node* array;
//
};
Visual Studio doesn't show linkage and doesn't recognize Node*. Is it ok to declare two separate classes in one .h file or is it better to implement the stack class nested inside the binary search tree class?
You've declared a struct called Node that is nested in the class BinarySearchTree, so if you want to refer to that struct outside of the class, you need to refer to it like this:
class stack
{
BinarySearchTree::Node* array;
//
};
Whether or not that's good design is a whole new question, so I would recommend getting a bit further with the implementation before asking more.
EDIT
Like you noticed, it's necessary to make the nested struct public if you want to use it outside of the class. That, in itself, is not necessarily bad or wrong. You're not exposing data, just a declaration.
You've got two choices:
Make the nested struct public.
Take the nested struct outside of the enclosing class.
Personally, I'd go for the first option.
I've made BSTs before. Can I use this to make a BST without modifications?
template <class Item>
class binary_tree_node
{
public:
private:
Item data_field;
binary_tree_node *left_ptr;
binary_tree_node *right_ptr;
};
I tried making a BST with this but ran into some problems. For one thing, when I create the root node, I can't access the pointers to its child nodes.
No, you won't be able to make a BST with a class that says "place public member functions here".
It won't even compile without some pretty hacky typedefs and macros.
Without modifications, no.
But that line 'place public member functions here' is screaming out that you should be modifying it.
Since you talk about permission problem, it means you are trying to use free functions. But since the pointers are private, you won't have access to them.
What you should be doing is creating member functions. For example:
class binary_tree_node
{
public:
binary_tree_node()
{
}
bool is_item_in_tree(const Item &item)
{
}
...
};
Anyway, I'd recommend reviewing your C++ basics around visibility and OOP.
Normally,you should provide the comparation interface for the new Item class,becuase in the insert and remove opeartion,the comparation are needed.
The concrete information was not given,so I do not know whether you use < and > etc relation operators or not.But If you use them.You should make sure the new Item class support these operators.
I'd advice you to add one generic comparation class name Comp to provide the compration interface for the Item class.