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