2010-08-15 16 views
2

Pour une classe X et un QSet < X *>, comment est-il possible de s'assurer que le QSet ne contient pas d'éléments dupliqués? La propriété unique dans chaque objet de type X est un QString qui peut être récupéré en utilisant getName().Duplicates dans QSet

J'ai implémenté la fonction qHash (X *), l'opérateur ==(), l'opérateur <() et l'opérateur>(), mais le QSet accepte toujours les éléments dupliqués, c'est-à-dire ceux ayant le même nom.

Quelqu'un pourrait-il m'aider à faire ce travail?


Ok. Voici ce que j'essaie de faire. J'ai une classe Y et une classe X, toutes deux héritant de QDialog. Une fonction de la classe Y (une fente) est responsable de la génération d'objets de la classe X. Le dialogue de Y doit être rendu responsable des objets X générés. Voilà pourquoi je créé un QSet < X *> membre Y.

Répondre

3

Le problème est que vous ne pouvez pas surcharger operator== comme ceci:

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

En effet, au moins un de l'argument doit être de classe type.

Puisque vous dites que vous avez mis en operator==, je suppose que vous avez fait quelque chose comme ceci:

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

Cet opérateur ne sera jamais appelé quand QSet essaie de Fiend doublons, car il a besoin d'un argument de gauche de type X et un droit de type

Je vois deux solutions possibles à ce problème:

  • Ne stockez pas vos éléments en tant que pointeurs (c'est-à-dire en utilisant QSet<X>). Cela vous permettra de surcharger les opérateurs corrects. Cette solution n'est cependant pas toujours réalisable.
  • Si vous pouviez faire valoir qu'il n'y a qu'un seul objet avec un identifiant donné, vous pouvez simplement stocker des pointeurs en vous QSet sans avoir à surcharger les opérateurs ni la fonction qHash.

Modifier: Si votre conception permet de créer plusieurs X -Objets avec le même identifiant, mais vous voulez qu'un seul objet d'exister à tout moment, peut-être il est préférable d'utiliser un QMap qui mappe de id . Lorsque vous créez un nouvel objet, faire quelque chose comme ceci:

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

+0

Une idée concernant l'implémentation de QSet <> :: contains() ?? Je veux dire comment vérifie-t-il si l'objet demandé est dans l'ensemble? –

+0

Dans votre cas (en utilisant 'QSet '), il calcule d'abord la valeur de hachage (en utilisant 'qHash (X *)'). Ensuite, il comparera toutes les entrées ayant cette valeur de hachage en utilisant la langue définie 'bool operator == (const X *, const X *)'. – Job

+0

J'ai essayé de le déboguer, mais aucune des fonctions n'est appelée. Pourquoi cela arrive-t-il? Je vais bananes !! –

0

En fonction de vos besoins précis, vous pouvez utiliser un vecteur avec Sorted std :: uniques (qui accepte un prédicat binaire personnalisé pour comparaison) .

+0

Ce serait un bon choix si je pouvais faire fonctionner la fonction QSet <> :: contains() –

0

Pourriez-vous utiliser QMap à la place? Votre boîte de dialogue aurait la variable de membre QMap<QString, X*> items.Ensuite, la vérification et la création de nouvelles de X serait comme:

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

Peut-être que ce n'est pas une solution aussi élégante que l'utilisation QSet pourrait être, mais je pense que cela est plus court et plus facile à comprendre.

+0

Oui, je viens d'implémenter ça seulement! –

-1

J'ai exactement le même problème. En fin de compte, je suis ici. Ma solution est très simple. Si la classe QSet ne peut pas faire ce que je veux, pourquoi ne pas utiliser l'objet dans ma classe avec du code ajouté à chaque fonction dont j'ai besoin. Voici ma solution:

Déclaration de Set classe:

#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; 

}; 

Définition de Set classe

#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; 

Il a travaillé pour moi très bien.

+0

Man, c'est tuer tous les avantages que QSet vous donne. pas créer une liste simple? –