Auf dieser Seite

Eigenschaftsschattierung und Überschreibungssemantik

Schattierung von Eigenschaften

Standardmäßig können Eigenschaften beschattet werden: Sie deklarieren eine Eigenschaft in einem abgeleiteten QML-Typ neu, möglicherweise mit einem neuen Typ und neuen Attributen. Das Ergebnis sind zwei Eigenschaften mit demselben Namen, von denen nur eine in einem bestimmten Kontext zugänglich ist. Das ist selten das, was Sie wollen. Oft ist es unbeabsichtigt, und meistens sind die Auswirkungen ziemlich verwirrend.

Betrachten wir das folgende Beispiel: Nehmen wir an, wir haben einen Typ Building, der in einer in QML geschriebenen Software zur Architekturvisualisierung verwendet wird:

// Building.qml
import QtQuick

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

Building ist ein Item, da es von diesem erbt, aber, was wichtig ist, die rotation property von Item wurde durch die neu eingeführte Rotationseigenschaft von Building verdrängt. Wenn dieses Objekt an eine generische Funktion übergeben wird, die Items behandelt, wird die Funktion versuchen, die Rotationseigenschaft des Objekts zu lesen und erwarten, dass sie die von Item definierte Eigenschaft vom Typ real zurückbekommt. Stattdessen erhält sie einen String zurück, was zu unerwarteten Ergebnissen führt.

Dies ist auch ein Hindernis für das QML-Tooling. Es kann den Typ einer Eigenschaft selten mit Sicherheit bestimmen, ohne den Code auszuführen, der die Eigenschaft manipuliert. Der Grund dafür ist, dass das Objekt, das die Eigenschaft enthält, oft von einem abgeleiteten Typ sein kann.

Dies verwirrt nicht nur den Benutzer und führt zu unerwarteten, schwer zu entdeckenden Fehlern, sondern hindert auch das Tooling daran, optimierten Code zu erzeugen.

Um dies zu beheben, wurden die Schlüsselwörter final, override und virtual - zusammen mit zusätzlichen Warnungen und Fehlern - eingeführt. Ihr Zweck ist es, den Benutzern zu helfen, versehentliches Shadowing zu vermeiden und explizite Mechanismen für die seltenen Fälle bereitzustellen, in denen eine Eigenschaft wirklich eine Eigenschaft eines Basistyps ersetzen muss. Wir bezeichnen ein solches explizites Shadowing als Overriding.

Hinweis: Wie oben erklärt, ist Shadowing oft unbeabsichtigt und führt in der Regel zu mehrdeutigem und schwer zu diagnostizierendem Verhalten. Bevorzugen Sie eindeutig benannte Eigenschaften gegenüber sowohl Shadowing als auch Overriding, wann immer dies möglich ist.

Schlüsselwörter Virtual, Override, Final

  • Das Schlüsselwort final kennzeichnet diese Deklaration als endgültig. Sie kann eine Eigenschaft eines Basistyps außer Kraft setzen, aber sie kann nicht von abgeleiteten Typen außer Kraft gesetzt oder überschattet werden. Dies hilft, versehentliches Shadowing zu verhindern und ermöglicht es den QML-Werkzeugen, optimierten Code zu generieren.
  • Das Schlüsselwort override zeigt an, dass die Eigenschaft absichtlich eine virtuelle Eigenschaft eines Basistyps außer Kraft setzt. Eine Eigenschaft, die eine andere außer Kraft setzt, muss nicht als virtual gekennzeichnet werden. Sie erbt automatisch die Virtualität der Eigenschaft, die sie außer Kraft setzt. Wenn die ursprüngliche Eigenschaft virtuell ist, ist auch die überschriebene Eigenschaft virtuell. Ist dies nicht der Fall, ist die Überschreibung ungültig und führt bereits zu einem Fehler.
  • Das Schlüsselwort virtual zeigt ausdrücklich an, dass die Eigenschaft überschrieben werden soll. Das Hinzufügen von virtual zur überschreibenden Eigenschaft hat keine Wirkung, siehe override.

So können sie in der Praxis verwendet werden:

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

Hinweis: Verwenden Sie lieber final als override

Hier ist auch eine umfangreiche Liste von Kombinationen von `virtual`, `override`, und `final` als Referenz:

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

Hinweis: Die meisten Warnungen werden in der Zukunft zu Fehlern werden, wir können sie wegen der Abwärtskompatibilität vorerst nicht in Fehler umwandeln.

Anmerkung: Diese Semantik wird von der QmlEngine erzwungen.

© 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.