Qt/Qml 和方法重载

2022-01-19 00:00:00 qt qml c++ moc

刚从 Qml 中调用重载的 C++ 方法并试图了解其背后的原因时,遇到了 Qt 框架的一个奇怪行为.假设我有一个类似 QList<QVariant> 的类,具有以下方法:

Just came across a weird behavior of Qt framework while invoking overloaded C++ methods from within Qml and trying to understand the reason behind it. Let's say I have a QList<QVariant>-like class with the following methods:

...
Q_SLOT void append(const QVariant &item);
Q_SLOT void append(const QVariantList &items);
Q_SLOT void insert(int index, const QVariant &item);
Q_SLOT void insert(int index, const QVariantList &items);
...

Qml:

onclicked: {
  var itemCount = myListObject.size();
  myListObject.insert(itemCount, "Item " + (itemCount + 1));
}

Qt 以某种方式决定调用 void insert(int index, const QVariantList &items) 重载,其中 items 参数设置为 a null QVariant 一个空的 QVariantList 而不是 void insert(int index, const QVariant &item) 重载与 QString包裹在 QVariant 中.

Qt somehow decides to invoke the void insert(int index, const QVariantList &items) overload with items argument set to a null QVariant an empty QVariantList instead of the void insert(int index, const QVariant &item) overload with QString wrapped in QVariant.

现在,如果我将声明的顺序更改如下,它会按预期工作:

Now if I change the order of declarations as follows, it works as expected:

Q_SLOT void insert(int index, const QVariantList &items);
Q_SLOT void insert(int index, const QVariant &item);

我在 Qt 框架的文档中找不到任何关于声明顺序以及它如何影响调用期间解决方法的方式.

I could not find anything under Qt framework's documentation regarding the order of declarations and how it affects the way methods are resolved during invoke.

谁能解释一下?谢谢.

推荐答案

这个问题与JavaScript中的重载有关.一旦你了解它――你就会明白代码的奇怪行为"的原因.只需看看 Javascript 中的函数重载 - 最佳实践.

This question is related to overloading in JavaScript. Once you get to known with it -- you understand reason of "weird behavior" of your code. Just take a look at Function overloading in Javascript - Best practices.

简单地说――我建议你接下来做:因为你可以在两边(QML和Qt/C++)操作QVariant变量――传递variant作为参数,并在Qt上处理它/C++ 端随心所欲.

In few words -- I recommend you to do next: since you can operate QVariant variables on both sides (QML and Qt/C++) -- pass variant as parameter, and process it on Qt/C++ side as you wish.

你可以这样使用:

您的 C++ 类创建并传递给 QML(例如,作为 setContextProperty("TestObject", &tc)):

Your C++ class created and passed to QML (e.g. as setContextProperty("TestObject", &tc)):

public slots:
    Q_SLOT void insert(const int index, const QVariant &something) {
        qDebug() << __FUNCTION__;
        if (something.canConvert<QString>()) {
            insertOne(index, something.toString());
        } else if (something.canConvert<QStringList>()) {
            insertMany(index, something.toStringList());
        }
    }

private slots:
    void insertOne(int index, const QString &item) {
        qDebug() << __FUNCTION__ << index << item;
    }

    void insertMany(int index, const QStringList &items) {
        qDebug() << __FUNCTION__ << index << items;
    }

您的 QML 中的某处:

Button {
    anchors.centerIn: parent
    text: "click me"
    onClicked: {
        // Next line will call insertOne
        TestObject.insert(1, "Only one string")
        // Next line will call insertMany
        TestObject.insert(2, ["Lots", "of", "strings"])
        // Next line will call insertOne
        TestObject.insert(3, "Item " + (3 + 1))
        // Next line will call insertOne with empty string
        TestObject.insert(4, "")
        // Next line will will warn about error on QML side:
        // Error: Insufficient arguments
        TestObject.insert(5)
    }
}

相关文章