Дубликаты в QSet - PullRequest
       44

Дубликаты в QSet

2 голосов
/ 16 августа 2010

Для класса X и QSet как можно убедиться, что QSet не содержит повторяющихся элементов?Уникальным свойством в каждом объекте типа X является QString, которую можно получить с помощью getName ().

Я реализовал функцию qHash (X *), operator == (), operator <()и operator> (), но QSet по-прежнему принимает дубликаты элементов, т. е. с одинаковыми именами.

Может кто-нибудь помочь мне в этой работе?


Хорошо.Вот что я пытаюсь сделать.У меня есть класс Y и класс X, оба из которых наследуют QDialog.Функция в классе Y (слот) отвечает за порождение объектов класса X. Диалог для Y должен нести ответственность за порождаемые объекты X.Вот почему я создал член QSet в Y.

Ответы [ 4 ]

3 голосов
/ 16 августа 2010

Проблема в том, что вы не можете перегрузить operator== следующим образом:

bool operator==(X*, X*);

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

Поскольку вы говорите, что выреализовано operator==, я полагаю, вы сделали что-то вроде этого:

struct X
{
    bool operator==(X*) const;
};

Этот оператор никогда не будет вызываться, когда QSet пытается найти дубликаты, потому что ему нужен левый аргумент типа X и правыйтипа X*

Я вижу два возможных решения этой проблемы:

  • Не храните ваши элементы в качестве указателей (то есть, используя QSet<X>).Это позволит вам перегрузить правильные операторы.Это решение, однако, не всегда выполнимо.
  • Если бы вы могли каким-то образом установить, что существует только один объект с заданным идентификатором, вы можете просто хранить указатели в вас QSet без необходимости перегрузки каких-либо операторов илиqHash function.

Edit : если ваш дизайн позволяет создавать несколько X -объектов с одинаковым идентификатором, но вы хотите, чтобы в любое время существовал только один такой объект, может быть, лучше использовать QMap, который отображается от id до X*.Когда вы создаете новый объект, делайте что-то вроде этого:

QString newId = ...;
delete objectsMap[newId];
objectsMap[newId] = new X(newId);

0 голосов
/ 15 марта 2014

У меня точно такая же проблема. В конце концов я попал сюда. Мое решение очень простое. Если класс QSet не может делать то, что я хочу, почему бы не использовать его объект в моем классе с добавлением кода для каждой функции, которая мне нужна. Вот мое решение:

Декларация класса Set:

#pragma once
#include<Plant.h>
#include<qset.h>
class Set
{
public:
    Set(void);
    ~Set(void);
    bool contains(Plant *plant);
    QSet<Plant*>::iterator insert(Plant *plant);
    QSet<Plant*>::iterator erase(Plant *plant);
private:
    QSet<Plant*> plants;

};

Определение класса Set

#include "Set.h"


Set::Set(void){
    plants = QSet<Plant*>();
}


Set::~Set(void){
}

bool Set::contains(Plant *plant){
    for(int i=0;i<plants.size();++i){
        if(plants.values().at(i)->compare(plant))
            return true;
    }
    return false;
}

QSet<Plant*>::iterator Set::insert(Plant *plant){
    if(!contains(plant))
        return plants.insert(plant);
}

QSet<Plant*>::iterator Set::erase(Plant *plant){
    QSet<Plant*>::iterator it;
    for(it = plants.begin();it!=plants.end();++it){
        if((*it)->compare(plant)){
            return plants.erase(it);
        }
    }
    return it;

Это сработало для меня очень хорошо.

0 голосов
/ 16 августа 2010

Не могли бы вы вместо этого использовать QMap?Ваш диалог будет иметь переменную-член QMap<QString, X*> items.Тогда проверка и создание новых X будет выглядеть следующим образом:

QString name = "foo";
if (!items.contains(name))
{
    items[name] = new X(name);
}
else
{
    // "foo" already exists
}

Возможно, это не такое элегантное решение, как использование QSet, но я думаю, что это короче и проще для понимания.

0 голосов
/ 16 августа 2010

В зависимости от ваших конкретных требований вы можете использовать отсортированный вектор вместе с std :: unique (который принимает для сравнения пользовательский двоичный предикат).

...