Doubly Linked Objects
I am trying to design an object with connections to parent and child
objects of the same class. I can't seem to produce an implementatin
without draw backs. It's code follows (along with some questions and
problems in comments):
#include <iostream>
class Node {
protected:
Node* parent;
Node* child;
std::string name;
private:
void init() {
parent = 0;
child = 0;
name = "";
}
public:
Node() {
init();
}
Node(const std::string name) {
init();
this->setName(name);
}
Node(const Node& node) {
init();
set(node);
}
virtual ~Node() {
// Q: Should I be concerned that the children may have been created
on the stack and passed in using the & operator?
if (getChild() != 0) {
delete getChild();
}
}
Node& operator=(const Node& node) {
set(node);
return *this;
}
void set(const Node &node) {
setName(node.getName());
if (node.getChild() != 0) {
Node* newChild = new Node(*node.getChild()); // Q: Is this
dangerous?
setChild(newChild);
}
}
void setName(const std::string& name) {
this->name = name;
}
std::string getName() const {
return name;
}
Node* getParent() const {
return parent;
}
void setParent(Node* node) {
parent = node;
}
Node* getChild() const {
return child;
}
void setChild(Node* node) {
child = node;
node->setParent(this);
}
// Using boost::shared_ptr<Node> would not work here because n=0 can
not return boost::shared_ptr<Node>(this);
Node* getDescendant(const int& n) {
if (n==0) {
return this;
} else if (getChild() != 0) {
return getChild()->getDescendant(n-1);
} else {
return 0;
}
}
void display(std::ostream& out) const {
out << "Node@" << this << "(name = " << getName().c_str() << ")";
if (getChild() != 0) {
out << std::endl << "|" << std::endl;
getChild()->display(out);
}
}
};
std::ostream& operator<<(std::ostream& out,const Node& node) {
node.display(out);
return out;
}
void test() {
Node a("A");
Node* b = new Node("B");
a.setChild(b);
// Uncommenting this creates an error because the code attemtps to
delete b through a's destructor and when it goes out of scope.
// Q: Should I be concerned by this.
//Node b("B");
//a.setChild(&b);
Node* c = new Node("C");
b->setChild(c); // We can do this because b was not copied into a
std::cout << a << std::endl << std::endl;
Node d(a);
std::cout << d << std::endl << std::endl;
std::cout << *d.getDescendant(2) << std::endl << std::endl;
// Q: Is it right that we rely on a's destructor to destroy b and c?
// delete(c); // Uncommenting this produces an error because the app
tries delete c twice.
}
int main(int argc, char* argv[]) {
test();
std::cout << "Finished" << std::endl;
return 0;
}
/* Output:
Node@0012FE54(name = A)
|
Node@003662F0(name = B)
|
Node@00366358(name = C)
Node@0012FE08(name = A)
|
Node@00366458(name = B)
|
Node@003664C0(name = C)
Node@003664C0(name = C)
Finished
*/
Does anyone have any responses to my anxious questions in the code
above? Am I worrying too much?
If I use references instead of pointers in the setChild and setParent
I then have to copy which would stop me creating the chain without
doing:
a.getChild().getChild().getChild().setParent(blah);
If I use smart pointers than I can't do the getDescendants function.
Any ideas on a nice implementation.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]