QSet 中的重复项

发布于 2024-09-14 14:38:35 字数 346 浏览 1 评论 0原文

对于 X 类和 QSet< X* >,如何确保QSet不包含重复元素? 每个 X 类型对象的唯一属性是一个可以使用 getName() 获取的 QString。

我已经实现了 qHash(X*) 函数、operator==()、operator<() 和operator>(),但 QSet 仍然接受重复元素,即具有相同名称的元素。

有人可以帮我完成这项工作吗?


好的。这就是我正在尝试做的事情。 我有一个Y类和一个X类,它们都继承了QDialog。 Y 类(槽)中的函数负责生成 X 类的对象。Y 的对话框将负责生成的 X 对象。这就是为什么我创建了 QSet< X*> Y 中的成员。

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 class 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

朦胧时间 2024-09-21 14:38:35

问题是你不能像这样重载operator==

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

这是因为至少有一个参数必须是类类型。

既然你说你实现了operator==,我想你做了这样的事情:

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

QSet尝试消除重复项时,这个运算符将永远不会被调用,因为它需要一个左参数类型 X 和类型 X* 的右侧

我可以看到此问题的两种可能的解决方案:

  • 不要将项目存储为指针(即使用 QSet) )。这将允许您重载正确的运算符。然而,这种解决方案并不总是可行。
  • 如果您可以以某种方式强制只有一个具有给定 id 的对象,那么您可以将指针存储在 QSet 中,而无需重载任何运算符或 qHash 函数。

编辑:如果您的设计允许创建多个具有相同 id 的 X 对象,但您只希望任何时候都存在一个这样的对象,也许最好使用 < code>QMap 从 id 映射到 X*。当您创建一个新对象时,请执行以下操作:

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

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 the qHash 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);

还给你自由 2024-09-21 14:38:35

根据您的具体要求,您可以将排序向量与 std::unique (接受自定义二进制谓词进行比较)一起使用。

Depending on your exact requirements, you could use a sorted vector together with std::unique (which accepts a custom binary predicate for comparison).

没有伤那来痛 2024-09-21 14:38:35

你能用QMap代替吗?您的对话框将具有成员变量 QMap;项目。然后检查和创建新的 X 会像这样:

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

也许这不像使用 QSet 那样优雅的解决方案,但我认为这更短且更容易理解。

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.

盛夏尉蓝 2024-09-21 14:38:35

我遇到了完全相同的问题。最后我到了这里。我的解决方案很简单。
如果 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;

它对我来说非常有效。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文