There exists an interface
#pragma once
#include <string>
#include <vector>
enum type_node {
NONTERMINAL;
TERMINAL;
}
class Node {
public:
Node(type_node);
virtual ~Node();
type_node node_type;
}
Node::Node(type_node TYPE) {
node_type = TYPE;
}
And two child classes
#pragma once
#include <Node.h>
class Nonterminal: public Node{
public:
Nonterminal();
~Nonterminal();
std::vector<Node *> children;
void attach(std::vector<Node *>);
}
#pragma once
#include "Node.h"
class Terminal: public Node{
public:
Terminal();
~Terminal();
}
Nonterminal is implemented as follows omitting the empty destructor.
NonterminalNode::NonterminalNode() : Node(NONTERMINAL) {
}
void NonterminalNode::attach(std::vector<Node *> CHILDREN) {
children = CHILDREN;
}
One would like to be able to populate a tree like structure
NonterminalNode * node_1 = new NonterminalNode;
NonterminalNode * node_2 = new NonterminalNode;
TerminalNode * node_3 = new TerminalNode;
node_1->attach({ node_2, node_3 });
Now a new sub-tree would like to be added to node_2 but accessed through node_1
NonterminalNode * node_1 = new NonterminalNode;
NonterminalNode * node_2 = new NonterminalNode;
TerminalNode * node_3 = new TerminalNode;
TerminalNode * node_4 = new TerminalNode;
TerminalNode * node_5 = new TerminalNode;
node_1->attach({ node_2, node_3 });
node_1->children[0]->attach({ node_4, node_5 }); // Error attach is not a virtual method
You could make attach
a virtual method and implement it in both classes but this violates good OOP practices as TerminalNode has no need for an attach method.
The interface-segregation principle (ISP) states that no client should be forced to depend on methods it does not use.
You could also use dynamic_cast
but this function could become expensive should you wish to add many sub-trees as the pointer conversion is nontrivial.
How can the desired behaviour be achieved without violating these two constraints?