本页内容

属性遮蔽与重写语义

属性遮蔽

默认情况下,属性可能会被遮蔽:您可以在派生 QML 类型中重新声明一个属性,可能赋予其新的类型和新的属性。结果将是两个同名的属性,但在任何给定上下文中只能访问其中一个。这通常并非您所期望的结果。 这通常是无意的,而且大多数情况下其影响会令人相当困惑。

考虑以下示例:假设我们在用 QML 编写的一款建筑可视化软件中使用了一个名为 Building 的类型:

// Building.qml
import QtQuick

Item {
    property int floors
    property string rotation // like CSS rotate, "-120deg"
    property date constructionDate
}

由于继承自 `Item`,`Building` 本身也是 `Item` 类型,但关键在于,Item 中的 `rotation property ` 已被 `Building` 中新引入的 `rotation` 属性所遮蔽。 当将此对象传递给处理 `Item` 的通用函数时,该函数会尝试读取对象的 `rotation` 属性,并期望返回由 `Item` 定义的 `real` 类型属性。然而,它实际返回的却是字符串,从而导致了意料之外的结果。

这也对 QML 工具链构成障碍。在不执行操作该属性的代码的情况下,工具链几乎无法确定该属性的类型。这是因为持有该属性的对象通常可能是派生类型。

因此,这不仅会混淆用户并导致难以察觉的意外错误,还会阻碍工具生成更优化的代码。

为解决此问题,引入了final 、override 和virtual 关键字,并增加了相应的警告和错误提示。其目的是帮助用户避免意外遮蔽,并为极少数情况下属性确实需要替换基类属性的情况提供显式机制。我们将此类显式遮蔽称为“覆盖”。

注意:如上所述 ,掩盖通常是无意的,且往往会导致行为模糊且难以诊断。因此,在可能的情况下,应优先采用名称唯一的属性,而非使用掩盖或重写。

Virtual、Override、Final 关键字

  • final 关键字将该声明标记为final。它可以覆盖基类的属性,但不能被派生类覆盖或遮蔽。这有助于防止意外遮蔽,并允许QML工具生成更优化的代码。
  • override 关键字表示该属性有意覆盖基类的虚拟属性。 覆盖其他属性的属性无需标记为 `virtual`。它会自动继承被覆盖属性的虚拟性。如果原始属性是虚拟的,则覆盖属性也是虚拟的;如果原始属性不是虚拟的,则覆盖属性无效并将引发错误。
  • virtual 关键字明确表示该属性旨在被重写。在重写属性上添加virtual 不会产生任何效果,详见override 。

以下是实际应用中的用法:

// Base.qml
QtObject {
 virtual property int a
 virtual property int b
 virtual property var c
 property var d
}

// DerivedMixed.qml
Base {
 override property var a // fine: overrides property "a" of a Base type
 final readonly property int b // fine: overrides property "c" of a Base type; can't be overriden any more
}

// DerivedDerivedMixed.qml
DerivedMixed {
 virtual property int a // warning: overrides virtual property, but lacks "override" or "final"
 override property int a // fine: overrides a property "a" of a DerivedMixed type;
 final property int a // fine: overrides a property "a" of a DerivedMixed type; can't be overriden any more

 virtual property int b // error: can't override a final property
 override property int b // error: can't override a final property
 final property int b // error: can't override a final property

 final property int c // fine: overrides property "c" of a Base type; can't be overriden any more
 override property int d // error: overrides a property that is not marked virtual
}

注意:建议 优先使用final 而不是override

以下还提供了一份关于 `virtual`、`override` 和 `final` 组合的详尽列表供参考:

// Base.qml
QtObject {
 property int a          // fine: declaring a property
 virtual property int b  // fine: declaring a property that is intended to be overriden
 final property int c    // fine: declaring a property that can't be overriden
 override property int d // error: does not override anything
 virtual override property int d // parser error: remove override
 virtual final property int d // parser error: virtual and final are mutually exclusive
}

// Derived.qml
Base {
 property int a // warning: overrides a property that is not marked virtual
 property int b // warning: overrides a virtual property, but lacks "override" or "final"
 property int c // error: can't override a final property
}

// DerivedVirtual.qml
Base {
 virtual property int a // warning: overrides a property that is not marked virtual
 virtual property int b // warning: overrides a virtual property, but lacks "override" or "final"
 virtual property int c // error: can't override a final property
}

// DerivedFinal.qml
Base {
 final property int a // warning: overrides a property that is not marked virtual
 final property int b // fine: overrides a property "b" from the Base type; can't be overriden any more
 final property int c // error: can't override a final property
}

// DerivedOverride.qml
Base {
 override property int a // error: overrides a property that is not marked virtual
 override property int b // fine: overrides a property "b" from the Base type
 override property int c // error: can't override a final property
 override final property int d // parser error: remove override
}

注意: 未来大多数 警告将变为错误,但出于向后兼容性的考虑,目前尚无法将其转换为错误。

注意:这些 语义由 QmlEngine 强制执行。

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.