Duplicates in QSet
For a class X and a QSet< X* >, how is it possible to make sure that the QSet doesn't contain duplicate elements? The unique property in each object of type X is a QString that can be fetched using getName().
I've implemented the qHash(X*) function, the operator==(), operator<() and operator>(), but the QSet still accepts duplicate elements, i.e., those with the same Name.
Could someone help me out in making this work?
Ok. Here's what I'm trying to do. I have a class Y and a class X, both of which inherit QDialog. A function in class Y ( a slot), is responsible for spawning objects of c开发者_开发技巧lass X. The dialog for Y is to be made responsible for the X objects spawned. This is why I created a QSet< X* > member in Y.
The problem is that you cannot overload operator==
like this:
bool operator==(X*, X*);
This is because at least one of the argument must be of class type.
Since you say you implemented operator==
, I suppose you did something like this:
struct X
{
bool operator==(X*) const;
};
This operator will never be called when QSet
tries to fiend duplicates because it needs a left argument of type X
and a right of type X*
I can see two possible solutions to this problem:
- Do not store your items as pointers (ie using
QSet<X>
). This will allow you to overload the correct operators. This solution, however, is not always feasible. - If you could enforce somehow that there is only one object with a given id, you could just store pointers in you
QSet
without needing to overload any operators nor theqHash
function.
Edit: If your design allows to create multiple X
-objects with the same id but you only want one such object to exist at any time, maybe it's best to use a QMap
which maps from id to X*
. When you create a new object, do something like this:
QString newId = ...;
delete objectsMap[newId];
objectsMap[newId] = new X(newId);
Depending on your exact requirements, you could use a sorted vector together with std::unique (which accepts a custom binary predicate for comparison).
Could you use QMap instead? Your dialog would have member variable QMap<QString, X*> items
. Then the checking and creating new X's would be like:
QString name = "foo";
if (!items.contains(name))
{
items[name] = new X(name);
}
else
{
// "foo" already exists
}
Maybe this is not as elegant solution as using QSet might be, but I think this is shorter and easier to understand.
I get exactly the same problem. In the end I get here. My solution is very simple. If class QSet can't do what I want, why don't use it object in my class with added code to every function I need. Here is my solution:
Declaration of Set class:
#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;
};
Definition of Set class
#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;
It worked for me very well.
精彩评论