3.2 Test tree creation

(Win version)

< 3.1 | 3.2 | 4.0 >

Try running the program again. You should get an error message that says something like cannot access private member declared in class strom::Node. This is because we are trying to change data members (such as _left_child) in Node objects from outside the Node class, and this is not allowed because those data members were declared in the private section of the Node class declaration.

We could easily fix this by simply commenting out the private: statement in the Node class declaration, thus making all those previously private attributes public. This is not a very elegant way of dealing with the problem because it eliminates all the benefits of having private data members in the first place (i.e. it prevents you or other programmers using your code from unintentionally modifying these variables).

Because Tree objects will legitimately need to make changes to their Node objects, we can make the Tree class a friend of the Node class. Friend classes are allowed to change the values of private data members. This effectively creates an exception to the privacy rules we established when creating the Node class.

You need to uncomment two lines in node.hpp to make Tree a friend of Node. Uncomment the bold blue lines shown below by removing the // at the beginning of each line:

#pragma once	

#include &lt;string&gt;
#include &lt;vector&gt;
#include  &lt;iostream&gt;
//#include "split.hpp"

namespace strom {

    <span style="color:#0000ff"><strong>class Tree;</strong></span>
    //class TreeManip;
    //class Likelihood;
    //class Updater;

    class Node {
            <span style="color:#0000ff"><strong>friend class Tree;</strong></span>
            //friend class TreeManip;
            //friend class Likelihood;
            //friend class Updater;

        public:
                                        Node();
                                        ~Node();

                    Node *              getParent()     {return _parent;}
                    Node *              getLeftChild()  {return _left_child;}
                    Node *              getRightSib()   {return _right_sib;}
                    int                 getNumber()     {return _number;}
                    std::string         getName()       {return _name;}
                    //Split               getSplit()      {return _split;}

                    double              getEdgeLength() {return _edge_length;}
                    void                setEdgeLength(double v);

            static const double _smallest_edge_length;

            typedef std::vector&lt;Node&gt;    Vector;
            typedef std::vector&lt;Node *&gt;  PtrVector;

        private:

            void                clear();

            Node *              _left_child;
            Node *              _right_sib;
            Node *              _parent;
            int                 _number;
            std::string         _name;
            double              _edge_length;
            //Split               _split;
    };

    inline Node::Node() {
        std::cout &lt;&lt; "Creating Node object" &lt;&lt; std::endl;
        clear();
    }

    inline Node::~Node() {
        std::cout &lt;&lt; "Destroying Node object" &lt;&lt; std::endl;
    }

    inline void Node::clear() {
        _left_child = 0;
        _right_sib = 0;
        _parent = 0;
        _number = -1;
        _name = "";
        _edge_length = _smallest_edge_length;
    }

    inline void Node::setEdgeLength(double v) {
        _edge_length = (v &lt; _smallest_edge_length ? _smallest_edge_length : v);
    }

}	

The first line simply assures the compiler that a class named Tree exists. Note that we have not included the tree.hpp header file, so the compiler does not have any idea what a Tree object is at this point. The alternative to adding this line would be to include the file tree.hpp, but that is complicated by the fact that tree.hpp includes node.hpp! The declaration above solves this chicken-and-egg issue, specifying exactly what Tree is in a situation where the compiler does not need to know anything more about Tree than the fact that it is the name of a class defined somewhere.

The second line tells the compiler that the class Tree is allowed to do whatever it likes with the private data members of Node.

After uncommenting those two lines in node.hpp, running the program should now produce this output:

Starting...
Constructing a Tree
Creating Node object
Creating Node object
Creating Node object
Creating Node object
Creating Node object
Creating Node object

Finished!
Destroying a Tree
Destroying Node object
Destroying Node object
Destroying Node object
Destroying Node object
Destroying Node object
Destroying Node object

Note that 1 Tree object and 6 Node objects were created and 1 Tree object and 6 Node objects were destroyed when the program finished.

Something to try

Try changing the tree by adding a node fourth_leaf as sister to third_leaf.

< 3.1 | 3.2 | 4.0 >