尽管QML支持“覆盖”属性和函数,但这种支持似乎有些笨拙。这是一个示例片段:

// T1.qml
QtObject {
    property int p: 1
    function f() { return 1 }
}

// T2.qml
T1 {
    property string p: "blah"
    function f() { return "blah" }
}


// usage
T1 {
    Component.onCompleted: {
        var obj = this
        for (var k in obj) console.log(k + " " + typeof obj[k] + " " + obj[k])
    }
}

T2 {
    Component.onCompleted: {
        var obj = this
        for (var k in obj) console.log(k + " " + typeof obj[k] + " " + obj[k])
    }
}

覆盖的行为是一致的-不管成员被覆盖了多少次,即使执行以下操作,您也始终会获得正确的覆盖:
QtObject {
    property T1 p : T2 {}
    Component.onCompleted: console.log(p.p + " " + p.f())
}

尽管该属性用类型T1声明,但它引用了一个T2对象,因此输出显示为“blah blah”。

它也可以基于“每个实例”进行工作:
T2 {
    function f() { return 1.5 }
    Component.onCompleted: {
       console.log(f())
    }
}

迭代T1的输出符合预期:
qml: objectName string
qml: p number 1
qml: objectNameChanged function function() { [code] }
qml: pChanged function function() { [code] }
qml: f function function() { [code] }

但是,T2的输出有点奇怪:
qml: objectName string
qml: p string blah
qml: p string blah
qml: objectNameChanged function function() { [code] }
qml: pChanged function function() { [code] }
qml: f function function() { [code] }
qml: pChanged function function() { [code] }
qml: f function function() { [code] }

它两次列出了“重写的”成员,但是,似乎其中一个不是来自“基本”类型,另一个似乎不是来自“派生”,因为p都是字符串。
var obj = this
for (var k in obj) if ((k === "f") && (typeof obj[k] === "function")) console.log(obj[k]())

调用两个f函数都会输出两次“blah”-因此,对于“override”函数也是如此。

我希望迭代“派生”对象将显示两次属性和功能,但是其中之一将来自基类型。让它们实际上重复,两者都指向同一个成员似乎是毫无意义且不合逻辑的。在实例级别进行覆盖将放置另一个成员,并且所有三个成员再次引用最新的覆盖。因此,从技术上讲,甚至无法手动选择替代。

所以我的问题是是否可以指定替代:
// in T2.qml - pseudocode
property string p: T1::p + "blah" //  value is "1 blah"
f() { return T1:: f() + "blah" } //  returning "1 blah"

尝试以幼稚的方式进行操作会导致史诗般的失败:
// in T2.qml
property string p: p + "blah" //  binding loop, p does not refer to T1's p
f() { return f() + "blah" } //  stack overflow, f does not refer to T1's f

最佳答案

找到了一个简单而天真的手动解决方案:

// T1.qml
QtObject {
    function f() { return f_t1() }
    function f_t1() { return 1 }
}

// T2.qml
T1 {
    function f() { return f_t2() }
    function f_t2() { return f_t1() + " blah " }
}

// usage
T2 {
    function f() { return f_t2() + 1.5}
    Component.onCompleted: console.log(f()) // outputs 1 blah 1.5
}

简而言之,为覆盖的每个“继承”级别显式命名函数,并使用非修饰的函数覆盖进行多态访问,因此,派生可以重用“基本”类型的实现。

10-07 19:44
查看更多