使用qSort遇到困难了

4

我有这段代码:

QVector<LogEvent *> currentItems;
//add a bunch of LogEvent objects to currentItems
qSort(currentItems.begin(), currentItems.end());

这是我的LogEvent类:

LogEvent.h:

//LogEvent.h
class LogEvent : public QTreeWidgetItem {

public:
    LogEvent();
    LogEvent(QDateTime, LogEvent *parent = 0);
    ~LogEvent();

    bool operator<(const LogEvent *);
    bool operator>(const LogEvent *);
    bool operator<=(const LogEvent *);
    bool operator>=(const LogEvent *);
    bool operator==(const LogEvent *);

private:

    QDateTime timestamp;
};

LogEvent.cpp:

//LogEvent.cpp
LogEvent::LogEvent()
{

}

LogEvent::LogEvent(QDateTime timestamp, LogEvent *parent)
    : QTreeWidgetItem(parent)
{
    this->timestamp = timestamp;
}

bool LogEvent::operator<(const LogEvent * event) {
    return (this->timestamp < event->timestamp);
}

bool LogEvent::operator>(const LogEvent * event) {
    return (this->timestamp > event->timestamp);
}

bool LogEvent::operator<=(const LogEvent * event) {
    return (this->timestamp <= event->timestamp);
}

bool LogEvent::operator>=(const LogEvent * event) {
    return (this->timestamp >= event->timestamp);
}

bool LogEvent::operator==(const LogEvent * event) {
    return (this->timestamp == event->timestamp);
}

在我进行排序之后,currentItems中的LogEvent对象没有被正确地排序。我非常确定我的运算符重载是正常的。

当我做这样的事情时:

std::cout << currentItems[0]<=currentItems[1]?"T":"F";

它将输出正确的值。

那么我做错了什么,如何纠正呢?

4个回答

7

qSort排序的是指针,而不是被这些指针所指向的对象。如果你想使用qSort对LogEvents进行排序,你需要按值存储它们,而不是按引用存储(并且还需要编写接受引用的比较运算符,因为qSort无法找到你的比较指针函数),或者传递一个由你定义的函数作为第三个参数。

可能需要通过示例来解释这一点。

LogEvent event1, event2;
LogEvent *eventptr1=&event1,*eventptr2=&event2;
event1<event2; // Operator not defined in your code
event1<eventptr2; // This will call the operator you have defined
eventptr1<eventptr2; // This will compare the pointers themselves, not the LogEvents. The pointers are not dereferenced here.

预计完成时间:为了方便接受单一完整的答案,我将从其他答案中摘取一些好的部分。

首先,定义一个标准语法小于运算符:

class LogEvent : public QTreeWidgetItem {

public:
  // ...
  bool operator<(const LogEvent *); // Non-standard, possibly reasonable for use in your own code.
  bool operator<(const LogEvent &); // Standard, will be used by most template algorithms.
  // ...
}

LogEvent.cpp

bool LogEvent::operator<(const LogEvent &event) {return timestamp<event.timestamp;}

完成这一步之后,您可以使用leemes答案中提供的dereference-and-compare模板:
template<class T>
bool dereferencedLessThan(T * o1, T * o2) {
    return *o1 < *o2;
}

要按以下方式对您的列表进行排序:

QVector<LogEvent *> currentItems;
//add a bunch of LogEvent objects to currentItems
qSort(list.begin(), list.end(), dereferencedLessThan<LogEvent>);

为了完整起见,最好为所有比较定义标准语法比较运算符。是否保留非标准比较运算符由您决定。

为了更完整,我认为可以定义一个通用的qSort<T>(QList<T*>)方法,但我不确定是否可能存在这样的重载声明,因为我对模板方法以及如何部分重载它们(或者称之为什么...)并不熟悉。如果可能的话,您永远不会意外地对指针进行排序,而不是它们后面的对象。 - leemes
也许可以定义一个(非成员)operator<(T*,T*),但我不确定是否可能。 - leemes
1
非成员运算符需要一个类或枚举参数。:( 然而,可以定义 operator<(LogEvent*, LogEvent) 以使其与 LogEvent::operator<(LogEvent*) 对称。 - 01d55

6
您可以定义一个比较函数,该函数接受两个(通用的)指针:
template<class T>
bool dereferencedLessThan(T * o1, T * o2) {
    return *o1 < *o2;
}

然后像这样调用:
void qSort ( RandomAccessIterator begin, RandomAccessIterator end, LessThan lessThan ) (点击查看文档)
qSort(list.begin(), list.end(), dereferencedLessThan<LogEvent>);

然后您可以使用此方法处理其他类型,而无需定义多个函数。

4

比较操作符应该使用const引用而不是指针吗?

在最后的代码片段中,您正在比较地址而不是值。


0

qSort函数要求项目类型(在上面的示例中为LogEvent)实现operator<()。 就像这样:

bool LogEvent::operator<(const LogEvent& event) {
    return timestamp < event.timestamp;
}

他使用了一个QVector<LogEvent*>而不是QVector<LogEvent> - leemes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接