Const函数最终通过友元类修改自身

Const function eventually modifies itself through friend class

本文关键字:修改 友元 函数 Const      更新时间:2023-10-16

在我的实现中,我有一个包含许多Node的主类Tree。每个Node包含一个指向下一个Node的指针,如果不实现则可以为NULL。Tree跟踪节点总数

通过Tree实现了一个返回Node指针的搜索函数。但是,如果Node还不存在,则创建一个新节点。这将增加Tree::m_totalnodes变量。然而,Tree::GetNode是const,但是这个修改没有提供任何警告、错误或运行时失败。这是什么原因(可能与tbNode::m_tree是非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;
};
Node* m_firstnode;

当您调用GetNode这样的const方法时,this将成为具有const资格的Tree const *类型。当您访问像m_totalnodes这样的成员时,它们看起来像unsigned int const一样是const限定的。不能修改对象。m_firstnode变成了Node * const:你不能修改指针,但是你仍然可以修改它指向的Node

如果想全面避免意外修改,可以通过重载getter函数访问m_firstnode:

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

(其他访问器样式也是可能的,这只是一个例子。但请注意,我不认为从第二个访问器返回Node const * const &是安全的;这可以编译,但它会返回一个对临时对象的引用。)

非const成员将调用第一个方法,并将看到一个指向可修改Node的可修改指针。const限定的成员将调用第二种方法,并将两者都视为不可修改的。

const只承诺方法本身不会改变数据成员。它没有说明Node对象不能更改数据成员(Node可以更改数据成员,因为它是友元)。