解决QML中的属性和函数“替代”

dte*_*ech 5 javascript overriding properties function qml

看起来,尽管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])
    }
}
Run Code Online (Sandbox Code Playgroud)

覆盖的行为是一致的-不管成员被覆盖了多少次,即使执行以下操作,也总是可以找到正确的成员:

QtObject {
    property T1 p : T2 {}
    Component.onCompleted: console.log(p.p + " " + p.f())
}
Run Code Online (Sandbox Code Playgroud)

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

它也可以基于“实例”工作:

T2 {
    function f() { return 1.5 }
    Component.onCompleted: {
       console.log(f())
    }
}
Run Code Online (Sandbox Code Playgroud)

迭代T1的输出符合预期:

qml: objectName string 
qml: p number 1
qml: objectNameChanged function function() { [code] }
qml: pChanged function function() { [code] }
qml: f function function() { [code] }
Run Code Online (Sandbox Code Playgroud)

但是,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] }
Run Code Online (Sandbox Code Playgroud)

它两次列出了“重写的”成员,但是,似乎其中一个不是来自“基础”类型,另一个似乎不是来自“派生”成员-因为两者p都是字符串。

var obj = this
for (var k in obj) if ((k === "f") && (typeof obj[k] === "function")) console.log(obj[k]())
Run Code Online (Sandbox Code Playgroud)

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"
Run Code Online (Sandbox Code Playgroud)

尝试以幼稚的方式进行操作会导致重大失败:

// 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
Run Code Online (Sandbox Code Playgroud)

dte*_*ech 7

找到了一种简单而幼稚的手动解决方案:

// 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
}
Run Code Online (Sandbox Code Playgroud)

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