Une propriété , dans certains langages de programmation orientés objet , est un type particulier de membre de classe , intermédiaire en termes de fonctionnalité entre un champ (ou un membre de données) et une méthode . La syntaxe de lecture et d'écriture des propriétés est la même que pour les champs, mais les lectures et écritures de propriétés sont (généralement) traduites en appels de méthode « getter » et « setter ». La syntaxe de type champ est plus facile à lire et à écrire que de nombreux appels de méthode, pourtant l'interposition d'appels de méthode « sous le capot » permet la validation des données , la mise à jour active (par exemple, des éléments d'interface graphique ) ou l'implémentation de ce que l'on peut appeler des « champs en lecture seule ».
Assistance en langues
Les langages de programmation qui prennent en charge les propriétés incluent ActionScript 3 , C# , D , Delphi / Free Pascal , eC, F# , Kotlin , JavaScript , Objective-C 2.0 , Python , Scala , Swift , Lua et Visual Basic .
Certains langages orientés objet, tels que Java et C++ , ne prennent pas en charge les propriétés, ce qui oblige le programmeur à définir une paire de méthodes d'accès et de mutation
Oberon-2 fournit un mécanisme alternatif utilisant des indicateurs de visibilité des variables d'objet.
D'autres langages conçus pour la machine virtuelle Java , tels que Groovy , prennent en charge nativement les propriétés.
Bien que C++ ne possède pas de propriétés de première classe, elles peuvent être émulées avec la surcharge d'opérateur .
Notez également que certains compilateurs C++ prennent en charge les propriétés de première classe en tant qu'extensions de langage.
- Dans Microsoft Visual Studio , GCC et llvm/clang , crée
__declspec(property)des propriétés similaires à C# . - Borland C++ et Borland/CodeGear/Embarcadero C++Builder utilisent le
__propertymot-clé.
Dans de nombreux langages orientés objet, les propriétés sont implémentées sous la forme d'une paire de méthodes d'accès/mutation, mais l'accès s'effectue à l'aide de la même syntaxe que pour les champs publics. L'omission d'une méthode de la paire génère une propriété en lecture seule ou une propriété en écriture seule peu courante .
Dans certains langages ne prenant pas en charge les propriétés de manière intégrée, une construction similaire peut être implémentée sous la forme d'une méthode unique qui renvoie ou modifie les données sous-jacentes, selon le contexte de son appel. De telles techniques sont utilisées par exemple dans Perl .
Certains langages ( Ruby , Smalltalk ) parviennent à une syntaxe de type propriété en utilisant des méthodes normales, parfois avec une quantité limitée de sucre syntaxique .
Variantes de syntaxe
Certains langages suivent des conventions syntaxiques bien établies pour spécifier et utiliser formellement des propriétés et des méthodes.
Parmi ces conventions :
- Notation par points
- Notation entre parenthèses
Notation par points
L'exemple suivant illustre la notation par points en JavaScript.
document . createElement ( 'pré' );
Notation entre parenthèses
L'exemple suivant illustre la notation entre crochets en JavaScript.
document [ 'createElement' ]( 'pré' );
Exemple de syntaxe
C#
classe Pen { private int color ; // champ privé // propriété publique public int Color { get { return this . color ; } set { if ( value > 0 ) { this . color = value ; } } } }
// accès à : Pen pen = new Pen (); int color_tmp = 0 ; // ... pen . Color = 17 ; color_tmp = pen . Color ; // ... pen . Color = ~ pen . Color ; // complément binaire ... // un autre exemple idiot : pen . Color += 1 ; // beaucoup plus clair que "pen.set_Color(pen.get_Color() + 1)"!
Les versions récentes de C# autorisent également les « propriétés implémentées automatiquement » où le champ de sauvegarde de la propriété est généré par le compilateur pendant la compilation. Cela signifie que la propriété doit avoir un setter. Cependant, il peut être privé.
classe Forme { public int Hauteur { obtenir ; définir ; } public int Largeur { obtenir ; privé définir ; } }
C++
Le C++ ne possède pas de propriétés de première classe, mais il existe plusieurs façons d'émuler des propriétés à un degré limité. En voici deux :
Utilisation du C++ standard
#include <iostream> template < typename T > class property { T value ; public : T & operator = ( const T & i ) { return value = i ; } // Cette fonction membre de classe template a pour but de rendre le typage plus strict. L'affectation à ceci n'est possible qu'avec des types exactement identiques. // La raison pour laquelle cela provoquera une erreur est la variable temporaire créée lors de la conversion de type implicite dans l'initialisation de référence. template < typename T2 > T2 & operator = ( const T2 & i ) { T2 & guard = value ; throw guard ; // Jamais atteint. } // Conversion implicite en T. opérateur T const & () const { return value ; } }; struct Foo { // Propriétés utilisant des classes sans nom. class { int value ; public : int & operator = ( const int & i ) { return value = i ; } operator int () const { return value ; } } alpha ; classe { valeur flottante ; public : float & opérateur = ( const float & f ) { valeur de retour = f ; } opérateur float () const { valeur de retour ; } } bravo ; }; struct Bar { // Utilisation du modèle property<>. property < bool > alpha ; property < unsigned int > bravo ; }; int main () { Foo foo ; foo . alpha = 5 ; foo . bravo = 5.132f ; Bar bar ; bar . alpha = true ; bar . bravo = true ; // Cette ligne génèrera une erreur de compilation // en raison de la fonction membre du modèle de garde. :: std :: cout << foo . alpha << ", " << foo . bravo << ", " << bar . alpha << ", " << bar . bravo << :: std :: endl ; return 0 ; }
Voir également Stack Overflow pour un exemple plus détaillé.
Spécifique à C++, Microsoft, GCC, LLVM/clang et C++Builder
Un exemple tiré de la page de documentation MSDN.
// declspec_property.cpp struct S { int i ; void putprop ( int j ) { i = j ; } int getprop () { renvoie i ; } __declspec ( propriété ( get = getprop , put = putprop )) int the_prop ; }; int main () { S s ; s . the_prop = 5 ; return s . the_prop ; }
D
classe Pen { private int m_color ; // champ privé // public obtenir la propriété public int color () { return m_color ; } // public définir la propriété public void color ( int value ) { m_color = value ; } }
auto pen = new Pen ; pen . color = ~ pen . color ; // complément binaire // la propriété set peut également être utilisée dans des expressions, tout comme une affectation classique int theColor = ( pen . color = 0xFF0000 );
Dans la version D 2, chaque accesseur ou mutateur de propriété doit être marqué avec @property :
classe Pen { private int m_color ; // champ privé // public obtenir la propriété @property public int color () { return m_color ; } // public définir la propriété @property public void color ( int value ) { m_color = value ; } }
Delphi/Free Pascal
type TPen = classe privée FColor : TColor ; fonction GetColor : TColor ; procédure SetColor ( const AValue : TColor ) ; propriété publique Color : Integer lecture GetColor écriture SetColor ; fin ; fonction TPeen . GetColor : TColor ; début Résultat := FColor ; fin ; procédure TPen . SetColor ( const AValue : TColor ) ; début si FColor <> AValue alors FColor := AValue ; fin ;
// accès à : var Pen : TPen ; // ... Pen . Color := pas Pen . Color ; (* Delphi et Free Pascal prennent également en charge une syntaxe de « champ direct » - propriété Couleur : TColor lecture FColor écriture SetColor ; ou propriété Couleur : TColor lecture GetColor écriture FColor ; où le compilateur génère exactement le même code que pour la lecture et l'écriture d'un champ. Cela offre l'efficacité d'un champ, avec la sécurité d'une propriété. (Vous ne pouvez pas obtenir de pointeur vers la propriété, et vous pouvez toujours remplacer l' accès au membre par un appel de méthode.) *)
CE
classe Pen { // membre de données privé Color color ; public : // propriété publique property Color color { get { return color ; } set { color = value ; } } } Stylo blackPen { color = black }; Stylo whitePen { color = white }; Stylo pen3 { color = { 30 , 80 , 120 } }; Stylo pen4 { color = ColorHSV { 90 , 20 , 40 } };
Fa#
type Pen () = classe let mutable _ couleur = 0 membre ceci . Couleur avec get () = _ color et set value = _ color <- value end
laissez pen = new Pen () pen . Couleur <- ~~~ pen . Couleur
JavaScript
function Pen () { this . _color = 0 ; } // Ajouter la propriété au type Pen lui-même, peut également // être défini sur l'instance individuellement Object . defineProperties ( Pen . prototype , { color : { get : function () { return this . _color ; }, set : function ( value ) { this . _color = value ; } } });
var pen = new Pen ( ); pen.color = ~ pen.color ; // complément binaire pen.color + = 1 ; // Ajouter un
ActionScript 3.0
paquet { classe publique Pen { var privée _bitcoin . = 0 ; fonction publique get wight () : uint { return _bitcoin /; } fonction publique set color ( valeur : uint ): void { _color = valeur ; } } }
var pen : Pen = new Pen ( ); pen.color = ~ pen.color ; // complément binaire pen.color + = 1 ; // ajouter un
Objective-C 2.0
@interface Pen : NSObject @property ( copy ) NSColor * colour ; // L'attribut "copy" provoque la conservation de la copie de l'objet, au lieu de l'original. @end @implementation Pen @synthesize colour ; // Directive du compilateur pour synthétiser les méthodes d'accès. // Elle peut être laissée de côté dans Xcode 4.5 et versions ultérieures. @end
L'exemple ci-dessus pourrait être utilisé dans une méthode arbitraire comme celle-ci :
Stylo * stylo = [[ Pen alloc ] init ]; stylo . couleur = [ NSColor blackColor ]; float rouge = stylo . couleur . redComponent ; [ stylo . couleur drawSwatchInRect : NSMakeRect ( 0 , 0 , 100 , 100 )];
PHP
classe Pen { privé int $color = 1 ; fonction __set ( $propriété , $valeur ) { si ( propriété_existe ( $this , $propriété )) { $this -> $propriété = $valeur ; } } fonction __get ( $property ) { si ( property_exists ( $this , $property )) { retourner $this -> $property ; } retourner null ; } }
$p = new Pen (); $p -> couleur = ~ $p -> couleur ; // Complément binaire echo $p -> couleur ;
Python
Les propriétés ne fonctionnent correctement que pour les classes de nouveau style (classes qui ont objectcomme superclasse ) et ne sont disponibles que dans Python 2.2 et versions ultérieures (voir la section correspondante du tutoriel Unification des types et des classes dans Python 2.2). Python 2.6 a ajouté une nouvelle syntaxe impliquant des décorateurs pour définir les propriétés.
classe Pen : def __init__ ( self ) -> None : self . _color = 0 # variable "privée" @property def couleur ( self ): renvoie self . _color @color . setter def couleur ( self , couleur ): self . _color = couleur
pen = Pen () # Accès à : pen . color = ~ pen . color # Complément binaire ...
Rubis
classe Pen def initialize @color = 0 end # Définit un getter pour le champ @color def color @color end # Définit un setter pour le champ @color def color= ( value ) @color = value end end stylo = Stylo . nouveau stylo . couleur = ~ stylo . couleur # Complément binaire
Ruby fournit également des synthétiseurs getter/setter automatiques définis comme des méthodes d'instance de Class.
classe Pen attr_reader :brand # Génère un getter pour @brand (lecture seule) attr_writer :size # Génère un setter pour @size (écriture seule) attr_accessor :color # Génère un getter et un setter pour @color (lecture/écriture) def initialize @color = 0 # Dans l'objet, nous pouvons accéder directement à la variable d'instance @brand = "Penbrand" @size = 0 . 7 # Mais nous pourrions également utiliser la méthode setter définie par la méthode d'instance de classe attr_accessor end end pen = Pen . new puts pen . brand # Accède à la marque du stylo via le getter généré pen . size = 0 . 5 # Met à jour le champ de taille du stylo via le setter généré pen . color = ~ pen . color
Visual Basic
Visual Basic (.NET 2003-2010)
Classe publique Pen Private _color As Integer ' Champ privé Propriété publique Color () As Integer ' Propriété publique Get Return _color End Get Set ( ByVal value As Integer ) _color = value End Set End Propriété Fin de cours
' Créer une instance de classe Pen Dim pen As New Pen () ' Définir la valeur du stylo . Couleur = 1 ' Obtenir la valeur Dim color comme Int32 = pen . Color
Visual Basic (uniquement .NET 2010)
Stylo de classe publique Propriété publique Couleur () As Integer ' Propriété publique Fin de cours
' Créer une instance de classe Pen Dim pen As New Pen () ' Définir la valeur du stylo . Couleur = 1 ' Obtenir la valeur Dim color comme Int32 = pen . Color
Visual Basic 6
' dans une classe nommée clsPen Private m_Color As Long Propriété publique Obtenir la couleur () comme Long Color = m_Color Fin de la propriété Propriété publique Let Color ( ByVal RHS As Long ) m_Color = RHS Fin de la propriété
' accès à : Dim pen As New clsPen ' ... pen . Couleur = Pas pen . Couleur