MyTetra Share
Делитесь знаниями!
Как поместить указатель на объект в QMap, и затем работать с этим объектом, извлекая указатель из QMap
Время создания: 25.01.2021 15:01
Автор: xintrea
Текстовые метки: qt, qt5, QMap, контейнер, указатель, объект, ссылка, поместить, извлечь
Раздел: Компьютер - Программирование - Язык C++ (Си++) - Библиотека Qt - Принципы написания кода
Запись: xintrea/mytetra_syncro/master/base/1611576089he7andd12f/text.html на raw.github.com

Бывает так, что в QMap надо разместить указатели на объекты, и по этим указателям работать с ними.


Например, в области видимости класса имеются следующие указатели на объекты:



protected:


QAction *actionDirectPreferencesMain =nullptr;

QAction *actionDirectPreferencesAppearance =nullptr;

QAction *actionDirectPreferencesCrypt =nullptr;

QAction *actionDirectPreferencesSyncro =nullptr;

QAction *actionDirectPreferencesRecordTable=nullptr;

QAction *actionDirectPreferencesAttach =nullptr;

QAction *actionDirectPreferencesKeyboard =nullptr;

QAction *actionDirectPreferencesHistory =nullptr;

QAction *actionDirectPreferencesMisc =nullptr;



Эти указатели нужно единообразно проинициализировать. Если делать инициализацию напрямую, то код будет выглядеть примерно так:



actionDirectPreferencesMain= new QAction("Main", this);

menu->addAction(actionDirectPreferencesMain] );


actionDirectPreferencesAppearance= new QAction("Appearance", this);

menu->addAction(actionDirectPreferencesAppearance] );


и т.д.



Это очень многословно, и нужно следить за правильными именами для каждого объекта. Гораздо лучше сделать инициализацию табличным способом. Т .е. вначале надо составить таблицу, потом пробежать по ее данным в цикле. Если использовать данные из цикла, тогда сами команды инициализации можно написать только один раз:



QMap< QString, QAction **> map;


map["Main"] = &actionDirectPreferencesMain;

map["Appearance"]= &actionDirectPreferencesAppearance;

map["Crypt"] = &actionDirectPreferencesCrypt;

map["Syncro"] = &actionDirectPreferencesSyncro;

map["Note Area"] = &actionDirectPreferencesRecordTable;

map["Attaches"] = &actionDirectPreferencesAttach;

map["Keyboard"] = &actionDirectPreferencesKeyboard;

map["History"] = &actionDirectPreferencesHistory;

map["Misc"] = &actionDirectPreferencesMisc;


for(auto pageName : map.keys())

{

*map[pageName] = new QAction(pageName, this);

menu->addAction( *map[pageName] );

}



Здесь следует обратить внимание на то, что внутри QMap будут храниться не просто указатели на объект, а указатель на указатель (**). Это сделано из-за того, что если хранить в QMap просто указатель на объект, то при изменении значения этого указателя, оригинальный указатель меняться не будет. Будет меняться только указатель, размещенный внутри QMap, а он никакого отношения к исходному указателю не имеет, за исключением того, что хранит тот же адрес объекта, что и исходный указатель, так как получил это значение в момент инициализации элемента QMap.


Поэтому в QMap хранится тип указатель на указатель (**), а инициализация таких указателей будет происходить путем записывания в элемент QMap адреса указателя (&) указателя на объект. И поэтому, для обращения к объекту по указателю внутри цикла, значение QMap надо разыменовывать.


Да, синтаксис получается немного запутанным, зато он позволяет работать с указателями на объекты, сохраненные в QMap.


Можно объяснить этот код другими словами.


Имеется несколько типов объектов, которые друг с другом взаимодействуют:



  • Первое - это место в памяти, где хранятся данные объекта QAction. Место в памяти определяется, как минимум, адресом первой ячейки памяти, начиная с которой хранятся данные.
  • Второе - это указатели. Указатель хранит адрес места в памяти, где находятся данные. Это то, что называется указателем на объект QAction *. Указатели на объеты хранятся в данном примере как свойства классов QAction *actionDirectPreferencesXXXXX.
  • Третье - это контейнер QMap<ключ, значение>, в котором в качестве значения нужно хранить некий тип, который позволит управляться с указателями на объекты QAction *. То есть, управляться с теми объектами, которые указаны во втором пункте.



Чтобы управляться с помощью QMap с какими-то объектами, необходимо в QMap хранить указатели на эти объекты. Получается, что если с помощью QMap нужно управляться с QAction *, то в QMap надо хранить указатель на QAction *. А это значит, что тип у такого значения должен быть QAction **.


Дальнейшее использование адресов и разыменовываний просто происходит из понимания того, какой тип значения хранится в QMap.


Так же в этом разделе:
 
MyTetra Share v.0.59
Яндекс индекс цитирования