LINUX.ORG.RU

Почему-то не вызываются НЕконстантные методы у объекта

 ,


0

2

Что-то не могу понять.

Есть список объектов. Работа с этим списком происходит по ссылке:

  // Перечень файлов и их свойств
  QList< Attach > *attachTable;

То есть, имеем не список ссылок на объекты, а обычный список объектов. Только работа с этим списком идет через ссылку (я пробовал и простой список делать, а не ссылку, результат тот же, только еще errorы вылазят, поэтому пока так как есть).

Проблема в том, что я могу вызвать метод объекта Attach, но только тот, который помечен как константный. То есть, у Attach есть два метода:

  QString getId() const;
  void pushFatDataToDisk();

Нормально компилируется вызов:

attachTable->at(i).getId()

И не компилируется вызов:

attachTable->at(i).pushFatDataToDisk()

Ошибка следующая:

../mytetra_develop/src/models/attachTable/AttachTableData.cpp: In member function 'void AttachTableData::switchAllAttachToLite()':
../mytetra_develop/src/models/attachTable/AttachTableData.cpp:115:42: error: passing 'const Attach' as 'this' argument of 'void Attach::pushFatDataToDisk()' discards qualifiers [-fpermissive]
     attachTable->at(i).pushFatDataToDisk();

Обычно похожие ошибки возникают если из константного метода вызывать неконстантный метод. Но тут ситуация вообще другая - метод, в котором происходит вызов - неконстантный. Выше по стеку тоже неконстантные методы. Поэтому из него можно вызывать любые методы. Но почему-то имеем ошибку.

Я попробовал вызвать неконстантный метод setupDataFromDom() у объекта, созданного напрямую. И он нормально вызывается. В коде есть такие строчки, которые нормально компилируются:

      // Создается объект аттача
      Attach attach(this);
      attach.setupDataFromDom(currentFile);

Я пробовал получить доступ к объекту в списке не через at(i), а по операнду [ i ]. И в принципе, проблема была решена:

    (*attachTable)[i].pushFatDataToDisk();

Но меня не покидает непонимание: почему через at(i) вызываются константные методы, а не константные вызваться не могут?

Код проекта:

https://github.com/xintrea/mytetra_dev/commit/f2a9cbd30b85d70208b6ad425abc3fd...

★★★★★

Работа с этим списком происходит по ссылке:
QList< Attach > *attachTable;

это указатель. и это важно.

почему через at(i) вызываются константные методы

потому что если посмотреть в документацию, то там написано:

const T & at(int i) const

т.е. at() всегда возвращает ссылку на объект-константу. если надо неконст - QList::operator[](int) или QList::value(int) (не забываем, что при этом будет выдана _копия_ Attach)

dib2 ★★★★★
()
Последнее исправление: dib2 (всего исправлений: 1)

Да, вот такая вот странная семантика у at() в Qt, совершенно непохожая на STL.

asaw ★★★★★
()
Ответ на: комментарий от annulen

с оператором[] будет не копия, а ссылка

То есть, кратко: at() - это константантная ссылка, а [] - это обычная ссылка? Правильно?

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Stil

Впрочем, если ты напишешь const T &v = list[i];, то тоже будет константный метод.

Stil ★★★★★
()
Ответ на: комментарий от dib2

const T & at(int i) const
т.е. at() всегда возвращает ссылку на объект-константу. если надо неконст - QList::operator[](int)

Вот тут два раза написан const.

Для меня указатели и ссылки - темный лес, за 20 лет так и не осилил, а обсудить не с кем.

Я не могу понять, вот ты говоришь - ссылка на объект-константу. Вопросы:

1. За счет чего объект становится константным - за счет первого или второго const?

2. Когда говорят о константных объектах, можно разделять две вещи: не будет изменяться ссылка на объект (по сути, не будет меняться адрес, который используется в ссылке), и не будет изменяться сам объект. Такое разделение есть в C/C++?

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Слушай, ну это же довольно просто.

class A
{
public:
    void foo(); // обычный метод
    void bar() const; // константный метод, т.е. не может менять члены  класса A
    const int baz(); // метод, возвращающий константу
}

1

За счёт const T&, возвращаемый T — константа

2

Смотри, читаем справа налево:


T t1; // обычная переменная типа T
const T t2; // константа типа T
T* t3; // указатель типа T
T* const t4; // константный указатель (не может указывать на другую область памяти)
const T* t5; // указатель на константу (не можем менять значение, лежащее по адресу через этот указатель)
const T *const t6; // константный указатель на константу

fluorite ★★★★★
()
Ответ на: комментарий от Xintrea

не будет изменяться ссылка на объект (по сути, не будет меняться адрес, который используется в ссылке)

Ссылки (T&) в этом смысле всегда константные, их нельзя переназначать. Указатели могут быть как константными (T*const), так и не константными(T*). При этом все они могут ссылаться на объект типа T, как на константу, запрещая вызов неконстантных методов (соответственно, const T&, const T*const, const T*)

annulen ★★★★★
()
Ответ на: комментарий от fluorite

Смотри, читаем справа налево:

Ну это ты так написал. Дугой прогер напишет по-другому:

T *t3; // указатель типа T
T *const t4; // константный указатель (не может указывать на другую область памяти)
const T *t5; // указатель на константу (не можем менять значение, лежащее по адресу через этот указатель)
const T* const t6; // константный указатель на константу

И результат будет тот же (вроде бы, не уверен). Только непонятно, почему одни пишут T* var, а другие T *var. И почему язык позволяет писать и так и так.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

И почему язык позволяет писать и так и так.

1. просто потому что.

2. потому что большую часть прошлого века было не принято в языках высокого уровня назначать семантику пробелам.

можешь выбрать ответ, который больше понравится

MyTrooName ★★★★★
()
Ответ на: комментарий от anonymous

Это глупо и избыточно, нужно просто:

У меня много мелких объектов Record. Мне выгоднее хранить в каждом объекте ссылку на QList, чем полную структуру всего QList. Это особенно влияет на производительность в мобильной версии приложения под Android.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Да, это одно и то же. Где стоит пробел, слева, или справа, или и слева и справа, значения не имеет. Есть ещё вариант T const* t, это то же самое, что и const T* t, обычно пишут последний вариант.

fluorite ★★★★★
()
Ответ на: комментарий от fluorite

Есть ещё вариант T const* t, это то же самое, что и const T* t

О боженьки, но как, почему, ради чего?

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Наследие C.

Essentially, the reason that the position of const within specifiers prior to an asterisk does not matter is that the C grammar was defined that way by Kernighan and Ritchie.

The reason they defined the grammar in this way was likely that their C compiler parsed input from left-to-right and finished processing each token as it consumed that. Consuming the * token changes the state of the current declaration to a pointer type. Encountering const after * means the const qualifier is applied to a pointer declaration; encountering it prior to the * means the qualifier is applied to the data pointed to.

Because the semantic meaning does not change if the const qualifier appears before or after the type specifiers, it is accepted either way.

fluorite ★★★★★
()
Ответ на: комментарий от Xintrea

Мне выгоднее хранить в каждом объекте ссылку на QList

прекрати путать указатели и ссылки. почитай книг на тему.

чем полную структуру всего QList.

QList - implicitly shared, т.е. его объект содержит в себе всего-лишь указатель и счетчик ссылок. На глаз это никак не повлияет на производительность, даже на Android

dib2 ★★★★★
()
Ответ на: комментарий от fluorite

Где стоит пробел, слева, или справа, или и слева и справа, значения не имеет

зато это предмет годного холивора в команде :)

dib2 ★★★★★
()
Ответ на: комментарий от dib2

А ещё всем лень перенастраивать IDE/редакторы. Сам подумываю вообще с двух сторон пробел ставить :)

jeuta ★★★★
()
Ответ на: комментарий от dib2

QList - implicitly shared, т.е. его объект содержит в себе всего-лишь указатель и счетчик ссылок. На глаз это никак не повлияет на производительность, даже на Android

(для ТС) И даже если взять обычный std::vector, то это тоже просто несколько указателей, которые при использовании как член класса просто лягут на место вектора. И в чем плюс - будет меньше беготни по памяти.

anonymous
()
Ответ на: комментарий от Xintrea

Мне выгоднее хранить в каждом объекте ссылку на QList, чем полную структуру всего QList. Это особенно влияет на производительность в мобильной версии приложения под Android.

Это ты так считаешь, на практике твой код будет потреблять больше памяти. sizeof( QList<T> ) внезапно равен sizeof( T* ). Т.е. выигрыша в размере Attach не будет ровно никакого. Зато будет прогрышь, ведь у тебя вместо одной аллокации будет две. А это не бесплатно. Кроме того будет проигрышь по скорости и масса возможностей для утечек памяти. Так что, повторюсь, не глупи.

anonymous
()
Ответ на: комментарий от Stil

То есть, кратко: at() - это константантная ссылка, а [] - это обычная ссылка? Правильно?

Да. Именно как и написано в документации. Srsly, bro.

А можно ссылочку на место, где это описано в документации?

ЕМНИП, единственное различие at() и operator[] состоит в том, что at() проверяет границы массива, а operator[] не проверяет. Больше отличий, вроде, нет. К чему здесь константные/неконстантные ссылки?

Kroz ★★★★★
()
Ответ на: комментарий от Kroz

ЕМНИП, единственное различие at() и operator[] состоит в том, что at() проверяет границы массива, а operator[] не проверяет. Больше отличий, вроде, нет. К чему здесь константные/неконстантные ссылки?

Это для STL, а мы тут Qt обсуждаем)

http://doc.qt.io/qt-5/qlist.html#at

http://doc.qt.io/qt-5/qlist.html#operator-5b-5d

http://doc.qt.io/qt-5/qlist.html#operator-5b-5d-2

А в STL у вектора есть неконстантный at

http://en.cppreference.com/w/cpp/container/vector/at

Stil ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.