En esta página

Sombreado de propiedades y semántica de sustitución

Sombreado de propiedades

Por defecto, las propiedades pueden ocultarse: Se vuelve a declarar una propiedad en un tipo QML derivado, posiblemente con un nuevo tipo y nuevos atributos. El resultado serán dos propiedades con el mismo nombre, sólo una de las cuales será accesible en un contexto dado. Esto rara vez es lo que se desea. A menudo es accidental, y la mayoría de las veces los efectos son bastante confusos.

Consideremos el siguiente ejemplo, digamos que tenemos un tipo Edificio utilizado en algún software de visualización arquitectónica escrito en QML:

// Building.qml
import QtQuick

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

Edificio es un Item ya que hereda de él pero, lo que es importante, la rotation property de Item ha sido ensombrecida por la recién introducida propiedad de rotación en Edificio. Al pasar este objeto a una función genérica que maneje elementos, la función intentará leer la propiedad de rotación del objeto y esperará obtener la propiedad de tipo real definida por Item. En lugar de ello, obtendrá una cadena, lo que conducirá a resultados inesperados.

Esto también es un obstáculo para las herramientas QML. Rara vez puede determinar con certeza el tipo de una propiedad sin ejecutar el código que la manipula. Esto se debe a que el objeto que contiene la propiedad a menudo puede ser de un tipo derivado.

Por lo tanto, esto no sólo confunde al usuario y da lugar a errores inesperados difíciles de detectar, sino que también impide que las herramientas generen código más optimizado.

Para solucionar este problema, se introdujeron las palabras clave final, override y virtual, junto con advertencias y errores adicionales. Su propósito es ayudar a los usuarios a evitar el shadowing accidental y proporcionar mecanismos explícitos para los raros casos en los que una propiedad realmente necesita reemplazar a una propiedad de un tipo base. Denominamos anulación a este tipo de anulación explícita.

Nota: Como se ha explicado anteriormente, el shadowing es a menudo accidental y normalmente conduce a un comportamiento ambiguo y difícil de diagnosticar. Siempre que sea posible, preferimos propiedades con nombre único en lugar de shadowing y overriding.

Palabras clave Virtual, Override, Final

  • La palabra clave final marca esta declaración como final. Puede sobrescribir una propiedad de un tipo base, pero no puede ser sobrescrita o sombreada por tipos derivados. Esto ayuda a evitar sombras accidentales y permite a las herramientas QML generar código más optimizado.
  • La palabra clave override indica que la propiedad anula intencionadamente una propiedad virtual de un tipo base. Una propiedad que sustituye a otra no necesita marcarse como virtual. Hereda automáticamente la virtualidad de la propiedad que reemplaza. Si la propiedad original es virtual, la sobreescritura también lo es. Si no lo es, la anulación no es válida y ya producirá un error.
  • La palabra clave virtual indica explícitamente que la propiedad está destinada a ser anulada. Añadir virtual en la propiedad que se desea anular no tiene ningún efecto, véase override.

Así es como pueden utilizarse en la práctica:

// 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
}

Nota: es preferible utilizar final en lugar de override

Aquí hay también una extensa lista de combinaciones de `virtual`, `override`, y `final` como referencia:

// 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
}

Nota: La mayoría de las advertencias se convertirán en errores en el futuro, no podemos convertirlas en errores por ahora debido a la compatibilidad con versiones anteriores.

Nota: Esta semántica es aplicada por 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.