Постоянный аргумент указателя на метод, который делегирует функцию removeAll().

Рассмотрим такой метод:

void Parent::removeChild(Child *child)
{
    children.removeAll(child);
}

В этом случае, поскольку child сам по себе никогда не модифицируется, его можно сделать константным указателем. Но так как children имеет тип QList, removeAll() принимает константную ссылку на неконстантный указатель.

Каков рекомендуемый способ справиться с этим? Пропустить константность аргумента метода или использовать const_cast константный указатель, чтобы он соответствовал методу removeAll()?


person Emil Eriksson    schedule 31.08.2010    source источник
comment
Когда вы говорите о константном указателе, вы имеете в виду const Child * или Child * const? Когда вы говорите, что константная ссылка на неконстантный указатель, вы имеете в виду Child * const & или что-то еще? Существует неотъемлемая двусмысленность, потому что указатель const строго означает T * const, но при случайном использовании может означать const T *.   -  person Philip Potter    schedule 01.09.2010
comment
Извините за путаницу. Я имею в виду указатель на константный дочерний элемент в качестве аргумента, в то время как removeAll() принимает «константную ссылку на указатель на неконстантный дочерний элемент». Я всегда забываю, какой синтаксис какой. Так что я говорю, очевидно, не о самом значении указателя, а об объекте, на который указывает, дочернем элементе.   -  person Emil Eriksson    schedule 01.09.2010
comment
Я не понимаю этого. Что такое QList, что он делает и откуда берется?   -  person David Thornley    schedule 03.09.2010
comment
Хорошо, я посмотрел, и тот факт, что это QList, не имеет ничего общего с тем, является ли указатель константным или нет. Предположительно children был объявлен как QList<Child *> или что-то в этом роде, и это важно. Показ фактического объявления children позволил бы избежать путаницы.   -  person David Thornley    schedule 03.09.2010


Ответы (3)


Сложный. Вы должны были добавить еще немного кода, но из документов я полагаю что у вас есть QList<Child*> и вы не можете изменить его на QList<const Child*>, потому что вам нужно получить доступ к фактическим объектам неконстантным образом.

Поскольку все, что делает функция removeAll(), это удаляет запись в списке и никоим образом не изменяет указанный Child (как это может быть, она ничего не знает о классе Child), здесь было бы безопасно использовать const_cast .

person Martin Ba    schedule 03.09.2010
comment
А теперь то, что я просил :) - person Emil Eriksson; 03.09.2010

Если вы хотите сказать, что изменение списка дочерних элементов не является изменением экземпляра Parent, просто сделайте список дочерних элементов mutable.

Однако убедитесь, что это действительно семантика, которую вы хотите для своего родительского класса. Если дети не являются частью состояния Parent (в семантике вашей системы), то все должно быть в порядке. Если это часть состояния экземпляра Parent, вы должны сохранить неконстантную функцию-член.

Ключевое слово mutable предназначено для тех исключительных случаев, когда член класса не следует воспринимать как состояние экземпляра, а только как дополнительную информацию. Если это ваш случай, то используйте его.

В противном случае пусть ваша функция-член будет неконстантной, поскольку она изменяет родительский член.

person Klaim    schedule 31.08.2010
comment
в дополнение к тому, что сказал @Billy, mutable позволяет методу const записывать данные, отличные от const. Он не позволяет методу, который принимает параметр const T *, преобразовывать его в T *. - person Philip Potter; 01.09.2010
comment
затем просто сделайте список детей изменяемым. Это член, который я предлагаю сделать изменяемым, если это желаемая семантика. Дело в том, что требуемое здесь приведение показывает, что Эмиль Эрикссон не хочет, чтобы родительский класс считался измененным, если его член children (QList AFAIU) изменен. Поэтому, чтобы сделать его функцию постоянной, ему действительно нужно сделать этот список изменяемым ИЛИ предположить, что изменение списка действительно меняет Родителя. В противном случае приведение const здесь является патчем, который только сделает вещи неочевидными для пользователей класса. - person Klaim; 01.09.2010

Похоже, что QList предназначен для использования с не указателями. Они определяют большую часть интерфейса, который является const как const T&, который прекрасно работал бы, если бы ваш QList был на Child, а не Child*.

Он будет отлично работать с указателями, но не может объявить константность для них. Я не рекомендую изменять ваш QList на Child, если только его копирование не обходится дешево, у вас есть вся правильная семантика для copy ctor, dtor, op=, op== и т. д., и вы не против иметь копии в списке, а не в объекты, которые вы передаете. Вы можете видеть, как с int или строками это будет работать так, как ожидалось (removeAll будет правильным const).

Если для вас важна корректность const, используйте const_cast. Затем объявите константную ссылку и передайте ее.

void Parent::removeChild(const Child *child)
{
    QList<Child*>::const_reference constRefToChild = const_cast<Child *> child;
    children.removeAll(constRefToChild);
}

Дело в том, что если removeAll когда-либо изменится, чтобы не принимать константу, вы получите ошибку компилятора. Тогда вы бы знали, что removeAll не сохраняет константность аргумента.

person Lou Franco    schedule 03.09.2010