Хобрук: Ваш путь к мастерству в программировании

Функция Const в конечном итоге изменяет себя через класс друзей

В моей реализации у меня есть основной класс Tree, который содержит много Node. Каждый Node содержит указатель на следующий Node, который может быть NULL, если не реализован. Tree отслеживает общее количество узлов.

Через Tree реализована функция поиска, которая возвращает указатель Node. Однако, если Node еще не существует, создается новый узел. Это увеличивает переменную Tree::m_totalnodes. Однако Tree::GetNode является константой, однако эта модификация не выдает никаких предупреждений, ошибок или сбоев во время выполнения. В чем причина этого (может быть, связано с тем, что tbNode::m_tree не является константой)?

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;
};
26.05.2014

Ответы:


1
Node* m_firstnode;

Когда вы вызываете метод const, такой как GetNode, this становится константным для типа Tree const *. Когда вы обращаетесь к таким элементам, как m_totalnodes, они кажутся константными, например unsigned int const. Вы не можете изменить объект. m_firstnode становится Node * const: вы не можете изменить указатель, но вы можете изменить Node, на который он указывает.

Если вы хотите полностью избежать случайных изменений, получите доступ к m_firstnode через перегруженную функцию получения:

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

(Возможны и другие стили методов доступа, это только один пример. Но обратите внимание, я не думаю, что было бы безопасно возвращать Node const * const & из второго метода доступа; это может скомпилироваться, но вернет ссылку на временный объект.)

Неконстантные члены вызовут первый метод и увидят модифицируемый указатель, указывающий на модифицируемый Node. Члены с квалификацией const будут вызывать второй и не будут рассматривать ни один из них как модифицируемый.

26.05.2014
  • В коде изменяется не m_firstnode, а Tree::m_totalnodes изменяется (в конечном итоге) через Tree::GetNode(). 26.05.2014
  • @DoubleYou Но это возможно только потому, что FindNode не является константным, и его вызывают через m_firstnode. Если вы хотите, чтобы это работало без изменения m_totalnodes, вам нужно добавить const-qualified FindNode, а затем вызвать его через соответствующую ссылку. 26.05.2014

  • 2

    Этот const только обещает, что сам метод не будет изменять элементы данных. Он ничего не говорит о том, что объект Node не меняет членов данных (что может сделать Node, поскольку он друг).

    26.05.2014
  • не могли бы вы описать дальше? Насколько я понимаю, метод const не может вызывать метод non-const. Если это не так, то для клиента этот код будет вводить в заблуждение. 26.05.2014
  • Все это означает, что неявный указатель this равен const, поэтому он не может вызывать какие-либо методы, отличные от const, и не может передавать this другой функции в качестве указателя, отличного от const. 26.05.2014
  • Новые материалы

    Управление состоянием в микрофронтендах
    Стратегии бесперебойного сотрудничества Микро-фронтенды — это быстро растущая тенденция в сфере фронтенда, гарантирующая, что удовольствие не ограничивается исключительно бэкэнд-системами..

    Декларативное и функциональное программирование в стиле LINQ с использованием JavaScript с использованием каррирования и генератора ...
    LINQ - одна из лучших функций C #, которая обеспечивает элегантный способ написания кода декларативного и функционального стиля, который легко читать и понимать. Благодаря таким функциям ES6,..

    Структуры данных в C ++ - Часть 1
    Реализация общих структур данных в C ++ C ++ - это расширение языка программирования C, которое поддерживает создание классов, поэтому оно известно как C с классами . Он используется для..

    Как я опубликовал свое первое приложение в App Store в 13 лет
    Как все началось Все началось три года назад летом после моего четвертого класса в начальной школе. Для меня, четвертого класса, лето кажется бесконечным, пока оно не закончится, и мой отец..

    Что в лицо
    Очерк о возвращении физиогномики и о том, почему мы должны это приветствовать. История начинается со странной науки. Р. Тора Бьорнсдоттир, Николас О. Рул. Видимость социального класса по..

    Почему шаблоны проектирования и почему нет?
    Сложность — мать всех проблем в программировании. Программное обеспечение должно быть разработано с точки зрения того, кто его поддерживает, а не того, кто его пишет, потому что программное..

    Создание дизайна обуви с помощью машинного обучения
    Обувь. Что подождать? Я думал, что речь пойдет о машинном обучении! Ну это так. Если бы вы пошли на Amazon, сколько обуви вы бы нашли? Наверное, много, не так ли? Но много ли в них..