QML中存在多态吗?

时间:2017-11-15 15:19:34

标签: qt pointers reference polymorphism qml

QML中是否存在多态和/或对象指针?我有一个班级A,有五个不同类别的成员,其中一个在任何特定时刻都可见。我在A中的属性依赖于可见成员中的属性(在所有成员中称为相同的东西)。

目前,我正在使用以下策略计算A中的所有此类属性:

import QtQuick 2.7

Rectangle {
    property int a: member1.visible ? member1.alpha + member1.beta :
                    member2.visible ? member2.alpha + member2.beta :
                    member3.visible ? member3.alpha + member3.beta :
                    member4.visible ? member4.alpha + member4.beta :
                    member5.visible ? member5.alpha + member5.beta :
                    0

    property int b: member1.visible ? member1.gamma * member1.delta :
                    member2.visible ? member2.gamma * member2.delta :
                    member3.visible ? member3.gamma * member3.delta :
                    member4.visible ? member4.gamma * member4.delta :
                    member5.visible ? member5.gamma * member5.delta :
                    0

    // Exactly one of these members have its visible-property set to true
    MySubClass1 {id: member1}
    MySubClass2 {id: member2}
    MySubClass3 {id: member3}
    MySubClass4 {id: member4}
    MySubClass5 {id: member5}
}

感觉就像它使用了比必要更多的代码,并且它不是非常易于维护,因为它很容易出错,因为我必须更新A中所有属性的表达式,如果我想添加或删除构件。

理想情况下(从做很多C ++编程的背景来看),我希望能够做到这样的事情:

import QtQuick 2.7

Rectangle {
    property <property-type> visibleMember:
        member1.visible ? member1 :
        member2.visible ? member2 :
        member3.visible ? member3 :
        member4.visible ? member4 :
        member5.visible ? member5 :
        0  // Shouldn't happen

    property int a: visibleMember.alpha + visibleMember.beta
    property int b: visibleMember.gamma * visibleMember.delta

    MySubClass1 {id: member1}
    MySubClass2 {id: member2}
    MySubClass3 {id: member3}
    MySubClass4 {id: member4}
    MySubClass5 {id: member5}
}

为了减少需要编写的代码量并增加可维护性,其中visibleMember将成为指针或某种对象的引用。或者甚至可能:

import QtQuick 2.7

Rectangle {
    property <property-type> visibleMember: NULL

    property int a: visibleMember !== NULL ? visibleMember.alpha + visibleMember.beta : 0
    property int b: visibleMember !== NULL ? visibleMember.gamma * visibleMember.delta : 0
}

并从类外部设置visibleMember(例如通过其父级),并以这种方式动态创建对象(如果可能),然后将其分配给visibleMember,而不是拥有可以分配给visibleMember的所有可能对象作为A中的潜在成员。

但是,我不确定<property-type>是什么,或者你是否可以像这样分配一个对象指针{(1)是否存在对象指针/引用,然后可以检查看它是否是visibleMember指针。至少是我试图以某种方式实现的事情的一部分吗?

2 个答案:

答案 0 :(得分:1)

如果所有类都继承了相同的基类,那么可以说QtObject可以轻松地将其用作属性类型。

您仍然可以访问基类中不存在的属性,因为具体对象保留其原始元信息。
然后,此元信息用于评估绑定。

如果您尝试访问未在要访问它的具体对象中定义的属性,它将评估为undefined。如果您尝试访问子属性,则会发出警告。

如果您没有任何公共基类,因为它可能也是stringint,您可以使用var作为该属性的数据类型。

  

出于性能原因,建议使用最接近的拟合/可能的数据类型。如果用于该属性的数据类型已具有您要在其中访问的属性,则可以优化绑定。

假设我们的基类是MyBaseClass,那么你可以写:

import QtQuick 2.7

Rectangle {
    property MyBaseClass visibleMember:
        member1.visible ? member1 :
        member2.visible ? member2 :
        member3.visible ? member3 :
        member4.visible ? member4 :
        member5.visible ? member5 :
        null  // Shouldn't happen

    property int a: visibleMember.alpha + visibleMember.beta
    property int b: visibleMember.gamma * visibleMember.delta

    MySubClass1 {id: member1}
    MySubClass2 {id: member2}
    MySubClass3 {id: member3}
    MySubClass4 {id: member4}
    MySubClass5 {id: member5}
}

如果该基类还具有预定义属性alpha, beta, gamma, delta,则可以优化ab的绑定。

当然,您也可以从外部设置该属性,因为您已在组件的根节点中公开该属性。

答案 1 :(得分:1)

为什么你需要这样做?看起来你正在滥用QML语言,你肯定会遇到性能问题。

请花点时间尝试了解QML语言及其与C ++的区别。

首先请注意

Rectangle {

    MySubClass1 {id: member1}
    MySubClass2 {id: member2}
}

绝对不等同于:

struct MyStruct: public Rectangle
{
    MySubClass1 member1;
    MySubClass2 member2;
}

但它更像是这样:

struct MyStruct: public Rectangle
{
    MyStruct()
    {
        children.insert("member1", new MySubClass1);
        children.insert("member2", new MySubClass2);
    }
    map<string, void *> children;
}

如果您在特定时间只需要会员,您可以这样做:

// MyComponent.qml
Rectangle {
    id: root
    property var visibleMember: InitialMember{} // If you can, replace var by the closest fitting data type

    property int a: visibleMember.alpha + visibleMember.beta
    property int b: visibleMember.gamma * visibleMember.delta

    function change1() {
        visibleMember.destroy();
        var component = Qt.createComponent("MySubClass1.qml");
        var object = component.createObject(root);
        visibleMember = object;
    }

    function change2() {
        visibleMember.destroy();
        var object = Qt.createQmlObject('import QtQuick 2.0; MySubClass2 {}', root);
        visibleMember = object;
    }
}

您还可以静态或动态地从外部设置visibleMember

MyComponent { // Assumming the code above is in MyComponent.qml
    visibleMember: SomethingElse {}
}

注意:如果这是MyComponent应该使用的方式,您可以删除change1()change2()甚至InitialMember{}来自MyComponent.qml

修改

与上述相同,但使用Loader代替Qt.createComponent()

Rectangle {
    id: root
    property var visibleMember: loader.item // If you can replace var by the closest fitting data type
    property alias source: loader.source // If you want to expose the loader source

    property int a: visibleMember.alpha + visibleMember.beta
    property int b: visibleMember.gamma * visibleMember.delta

    function change1() {
        loader.source = "MySubClass1.qml";
    }

    function change2() {
        loader.source = "MySubClass2.qml";
    }

    Loader {
        id: loader
    }
}