0

In my implementation I have a main class Tree which contains many Nodes. Each Node contains a pointer to the next Node, which can be NULL if not implemented. Tree keeps track of the total amount of nodes.

Through the Tree a search function is implemented which returns the Node pointer. However if the Node does not exist yet, a new node is created. This increments the Tree::m_totalnodes variable. However, Tree::GetNode is const, yet this modification does not provide any warnings, errors or runtime failures. What is the reason for this (maybe related that tbNode::m_tree is non-const)?

class Node;             //forward declare

class Tree {
public:
    Tree() : m_totalnodes(0) {
        m_firstnode =  new Node(this,0);
    }
    Node* GetNode(int nodenumber) const {           //note const! Should not modify Tree
        return m_firstnode->FindNode(nodenumber);   //this function eventually modifies it (and no warning)
    }
private:
    friend class Node;
    unsigned int m_totalnodes;
    Node* m_firstnode;
};

class Node {
public:
    Node(Tree *thetree, int nodenumber) : m_tree(thetree),  m_nextnode(NULL), m_nodenumber(nodenumber) {
        m_tree->m_totalnodes++;
    }
    Node* FindNode(int nodenumber) {
        if (!m_nextnode)
            m_nextnode =  new Node(m_tree, nodenumber);
        return m_nextnode;
    }
private:
    Tree* m_tree;
    Node* m_nextnode;
    unsigned int m_nodenumber;
};
DoubleYou
  • 1,057
  • 11
  • 25

2 Answers2

1

That const only promises that the method itself is not going to change the data members. It does not say anything about a Node object not changing data members (which the Node can, since it's a friend).

user657267
  • 20,568
  • 5
  • 58
  • 77
LaszloLadanyi
  • 973
  • 4
  • 12
  • could you plz describe a further? To my understanding, a `const` method can not call any `non-const` method. If this is not the case, then to the client of this code, it will be misleading. – Rakib May 26 '14 at 02:55
  • 2
    All it means is the implicit `this` pointer is `const`, so it cannot call any non-`const` methods on itself, nor can it pass `this` to another function as a non-`const` pointer. – etheranger May 26 '14 at 03:02
1
Node* m_firstnode;

When you call a const method like GetNode, this becomes const-qualified to type Tree const *. When you access members like m_totalnodes, they appear to be const-qualified like unsigned int const. You cannot modify the object. m_firstnode becomes Node * const: you cannot modify the pointer, but you can still modify the Node it points to.

If you want to comprehensively avoid accidental modification, access m_firstnode through an overloaded getter function:

Node * & firstnode() { return m_firstnode; }
Node const * firstnode() const { return m_firstnode; }

(Other accessor styles are possible, this is just one example. But note, I don't think it would be safe to return Node const * const & from the second accessor; this may compile but it would return a reference to a temporary.)

Non-const members will call the first method, and will see a modifiable pointer pointing to a modifiable Node. Const-qualified members will call the second, and see neither as modifiable.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • In the code it is not `m_firstnode` that gets modified, it is `Tree::m_totalnodes` that gets modified (evantually) through `Tree::GetNode()`. – DoubleYou May 26 '14 at 03:16
  • @DoubleYou But this is only possible because `FindNode` is not const-qualified and it gets called thorugh `m_firstnode`. If you want to make it work without `m_totalnodes` getting changed, you need to add a const-qualified `FindNode` and then call that through an appropriate link. – Potatoswatter May 26 '14 at 03:18