Una propiedad , en algunos lenguajes de programación orientados a objetos , es un tipo especial de miembro de clase , intermedio en funcionalidad entre un campo (o miembro de datos) y un método . La sintaxis para leer y escribir propiedades es como para los campos, pero las lecturas y escrituras de propiedades se traducen (normalmente) en llamadas a métodos ' getter ' y ' setter '. La sintaxis similar a la de los campos es más fácil de leer y escribir que muchas llamadas a métodos, [ cita requerida ] sin embargo, la interposición de llamadas a métodos "de forma oculta" permite la validación de datos , la actualización activa (por ejemplo, de elementos de la GUI ) o la implementación de lo que se puede llamar "campos de solo lectura".
Soporte en idiomas
Los lenguajes de programación que admiten propiedades incluyen ActionScript 3 , C# , D , Delphi / Free Pascal , eC, F# , Kotlin , JavaScript , Objective-C 2.0 , Python , Scala , Swift , Lua y Visual Basic .
Algunos lenguajes orientados a objetos, como Java y C++ , no admiten propiedades, lo que requiere que el programador defina en su lugar un par de métodos de acceso y mutación . [1] [ cita requerida ]
Oberon-2 proporciona un mecanismo alternativo que utiliza indicadores de visibilidad de variables de objeto. [ cita requerida ]
Otros lenguajes diseñados para la máquina virtual Java , como Groovy , admiten propiedades de forma nativa.
Si bien C++ no tiene propiedades de primera clase, éstas se pueden emular con sobrecarga de operadores . [2]
Tenga en cuenta también que algunos compiladores de C++ admiten propiedades de primera clase como extensiones del lenguaje. [ cita requerida ]
- En Microsoft Visual Studio , [3] GCC y llvm/clang , [4] crean
__declspec(property)propiedades similares a C# . - Borland C++ y Borland/CodeGear/Embarcadero C++Builder utilizan la
__propertypalabra clave. [5]
En muchos lenguajes orientados a objetos, las propiedades se implementan como un par de métodos de acceso/mutación, pero se accede a ellos utilizando la misma sintaxis que para los campos públicos. Si se omite un método del par, se obtiene una propiedad de solo lectura o una propiedad de solo escritura poco común .
En algunos lenguajes que no tienen soporte integrado para propiedades, se puede implementar una construcción similar como un método único que devuelve o cambia los datos subyacentes, según el contexto de su invocación. Estas técnicas se utilizan, por ejemplo, en Perl . [ cita requerida ]
Algunos lenguajes ( Ruby , Smalltalk ) logran una sintaxis similar a una propiedad utilizando métodos normales, a veces con una cantidad limitada de azúcar sintáctica .
Variantes de sintaxis
Algunos lenguajes siguen convenciones sintácticas bien establecidas para especificar y utilizar formalmente propiedades y métodos.
Entre estas convenciones:
- Notación de puntos
- Notación entre corchetes
Notación de puntos
El siguiente ejemplo demuestra la notación de puntos en JavaScript.
documento .createElement ( 'pre' ) ;
Notación entre corchetes
El siguiente ejemplo demuestra la notación entre corchetes en JavaScript.
documento [ 'createElement' ]( 'pre' );
Ejemplo de sintaxis
DO#
clase Pen { int privado color ; // campo privado // propiedad pública int público Color { obtener { devolver este . color ; } establecer { si ( valor > 0 ) { este . color = valor ; } } } }
// accediendo a:
Pen pen = new Pen (); int color_tmp = 0 ; // ... pen . Color = 17 ; color_tmp = pen . Color ; // ... pen . Color = ~ pen . Color ; // complemento bit a bit ...
// otro ejemplo tonto:
pen . Color += 1 ; // ¡mucho más claro que "pen.set_Color(pen.get_Color() + 1)"!
Las versiones recientes de C# también permiten "propiedades implementadas automáticamente" en las que el compilador genera el campo de respaldo de la propiedad durante la compilación. Esto significa que la propiedad debe tener un definidor. Sin embargo, puede ser privado.
clase Forma { int público Altura { obtener ; establecer ; } int público Ancho { obtener ; establecer ; } }
C++
C++ no tiene propiedades de primera clase, pero existen varias formas de emular propiedades en un grado limitado. Dos de ellas son las siguientes:
Usando C++ estándar
#include <flujo de datos>
plantilla < typename T > propiedad de clase { T valor ; público : T & operador = ( const T & i ) { valor de retorno = i ; } // Esta función miembro de clase de plantilla tiene como finalidad hacer que la tipificación sea más estricta. La asignación a esta función solo es posible con tipos exactamente idénticos. // La razón por la que provocará un error es la variable temporal creada durante la conversión de tipo implícita en la inicialización de la referencia. plantilla < typename T2 > T2 & operador = ( const T2 & i ) { T2 & guard = valor ; throw guard ; // Nunca se alcanza. }
// Conversión implícita de nuevo a T.
operador T const & () const { valor de retorno ; } };
struct Foo { // Propiedades que utilizan clases sin nombre. clase { int valor ; público : int & operador = ( const int & i ) { valor de retorno = i ; } operador int () const { valor de retorno ; } } alfa ;
clase { valor flotante ; público : flotante y operador = ( const flotante y f ) { valor de retorno = f ; } operador flotante () const { valor de retorno ; } } bravo ; };
struct Bar { // Usando la propiedad<>-template. propiedad < bool > alpha ; propiedad < unsigned int > bravo ; };
int main ( ) { Foo foo ; foo.alpha = 5 ; foo.bravo = 5.132f ;
Bar bar ; bar . alpha = true ; bar . bravo = true ; // Esta línea producirá un error de tiempo de compilación // debido a la función miembro de plantilla de protección. :: std :: cout << foo . alpha << ", " << foo . bravo << ", " << bar . alpha << ", " << bar . bravo << :: std :: endl ; return 0 ; }
Consulte también Stack Overflow para ver un ejemplo más detallado.
C++, Microsoft, GCC, LLVM/clang y C++Builder específico
Un ejemplo tomado de la página de documentación de MSDN.
// declspec_property.cpp
estructura S { int i ; void putprop ( int j ) { i = j ; }
int getprop () { devolver i ; }
__declspec ( propiedad ( obtener = getprop , poner = putprop )) int the_prop ; };
int main () { S s ; s . la_propiedad = 5 ; devolver s . la_propiedad ; }
D
clase Pen { private int m_color ; // campo privado // propiedad pública get public int color () { return m_color ; } // propiedad pública set public void color ( int value ) { m_color = value ; } }
auto pen = new Pen ; pen . color = ~ pen . color ; // complemento bit a bit
// la propiedad establecida también se puede usar en expresiones, al igual que la asignación regular
int theColor = ( pen . color = 0xFF0000 );
En la versión 2 de D, cada descriptor de acceso o mutador de propiedad debe estar marcado con @property:
clase Pen { int privado m_color ; // campo privado // propiedad pública obtenida @propiedad pública int color () { devolver m_color ; } // propiedad pública establecida @propiedad pública void color ( int valor ) { m_color = valor ; } }
Delphi/Pascal libre
tipo TPen = clase privada FColor : TColor ; función GetColor : TColor ; procedimiento SetColor ( const AValue : TColor ) ; propiedad pública Color : Integer leer GetColor escribir SetColor ; fin ;
función TPen . GetColor : TColor ; inicio Resultado := FColor ; fin ;
procedimiento TPen . SetColor ( const AValue : TColor ) ; comienzo si FColor <> AValue entonces FColor := AValue ; fin ;
// accediendo:
var Pen : TPen ; // ... Pen . Color := no Pen . Color ;
(*
Delphi y Free Pascal también admiten una sintaxis de 'campo directo' -
propiedad Color: TColor leer FColor escribir SetColor;
o
propiedad Color: TColor leer GetColor escribir FColor;
donde el compilador genera exactamente el mismo código que para leer y escribir
un campo. Esto ofrece la eficiencia de un campo, con la seguridad de una propiedad.
(No se puede obtener un puntero a la propiedad y siempre se puede reemplazar el
acceso al miembro con una llamada a un método).
*)
CE
clase Pluma { // miembro de datos privados Color color ; público : // propiedad pública propiedad Color color { obtener { devolver color ; } establecer { color = valor ; } } } Pluma PlumaNegra { color = negro }; Pluma PlumaBlanca { color = blanco }; Pluma Pluma3 { color = { 30 , 80 , 120 } }; Pluma Pluma4 { color = ColorHSV { 90 , 20 , 40 } };
F#
tipo Pen () = clase let mutable _ color = 0
Miembro de este . Color con get () = _ color y set value = _ color <- value end
deje que lapiz = new Lapiz ( ) lapiz.Color < - ~~~ lapiz.Color
JavaScript
function Pen () { this._color = 0 ; } // Agrega la propiedad al tipo Pen en sí, también se puede // establecer en la instancia individualmente Object.defineProperties ( Pen.prototype , { color : { get : function ( ) { return this._color ; } , set : function ( value ) { this._color = value ; } } } ) ;
var pen = new Pen (); pen . color = ~ pen . color ; // complemento bit a bit pen . color += 1 ; // Agregar uno
ActionScript 3.0
paquete { clase pública Pen { var privada _bitcoin . = 0 ; función pública obtener peso (): uint { devolver _bitcoin /; } función pública establecer color ( valor : uint ): void { _color = valor ; } } }
var pen : Pen = new Pen (); pen . color = ~ pen . color ; // complemento bit a bit pen . color += 1 ; // suma uno
Objetivo-C 2.0
@interface Pen : NSObject
@property ( copy ) NSColor * colour ; // El atributo "copy" hace que se conserve la copia del objeto, en lugar del original. @end
@implementation Pen
@synthesize colour ; // Directiva del compilador para sintetizar métodos de acceso. // Se puede omitir en Xcode 4.5 y versiones posteriores. @end
El ejemplo anterior podría usarse en un método arbitrario como este:
Pluma * pluma = [ [ Pluma alloc ] init ] ; pluma.color = [ NSColorblackColor ] ; float rojo = pluma.color.redComponent ; [ pluma.color drawSwatchInRect : NSMakeRect ( 0 , 0 , 100 , 100 ) ] ;
PHP
clase Pluma
{
int privado $color = 1 ;
función __set ( $propiedad , $valor )
{
si ( propiedad_existe ( $esta , $propiedad )) {
$esta -> $propiedad = $valor ;
}
}
función __get ( $propiedad )
{
si ( propiedad_existe ( $this , $propiedad )) {
devolver $this -> $propiedad ;
}
devolver null ;
}
}
$p = new Pen ();
$p -> color = ~ $p -> color ; // Complemento bit a bit
echo $p -> color ;
Pitón
Las propiedades solo funcionan correctamente para las clases de estilo nuevo (clases que tienen objectcomo superclase ) y solo están disponibles en Python 2.2 y versiones posteriores (consulte la sección correspondiente del tutorial Unificación de tipos y clases en Python 2.2). Python 2.6 agregó una nueva sintaxis que involucra decoradores para definir propiedades.
clase Pen :
def __init__ ( self ) -> None :
self._color = 0 # variable " privada"
@property
def color ( self )
: devuelve self._color
@color . setter
def color ( self , color ):
self . _color = color
pen = Pen ()
# Accediendo a:
pen . color = ~ pen . color # Complemento bit a bit ...
Rubí
clase Pen def initialize @color = 0 fin # Define un captador para el campo @color def color @color fin
# Define un definidor para el campo @color
def color= ( valor ) @color = valor fin fin
pluma = Pluma . nuevo pluma . color = ~ pluma . color # Complemento bit a bit
Ruby también proporciona sintetizadores getter/setter automáticos definidos como métodos de instancia de clase.
clase Pen attr_reader :brand # Genera un captador para @brand (solo lectura) attr_writer :size # Genera un definidor para @size (solo escritura) attr_accessor :color # Genera un captador y definidor para @color (lectura/escritura)
def initialize @color = 0 # Dentro del objeto, podemos acceder directamente a la variable de instancia @brand = "Penbrand" @size = 0 . 7 # Pero también podríamos usar el método setter definido por el método de instancia de clase attr_accessor end end
pen = Pen . new puts pen . brand # Accede a la marca del bolígrafo a través del getter generado pen . size = 0 . 5 # Actualiza el campo de tamaño del bolígrafo a través del setter generado pen . color = ~ pen . color
Visual Basic
Visual Basic (.NET 2003–2010)
Clase pública Pen Private _color como entero ' Campo privado
Propiedad pública Color () Como entero ' Propiedad pública Obtener Retorno _color Fin Obtener Establecer ( PorVal valor Como entero ) _color = valor Fin Establecer Fin Propiedad
Fin de clase
' Crear instancia de clase Pen
Dim pen As New Pen ()
' Establecer valor
de lápiz . Color = 1
' Obtener valor
Dim color como Int32 = pen . Color
Visual Basic (sólo .NET 2010)
Bolígrafo de clase pública
Propiedad pública Color () Como entero ' Propiedad pública
Fin de clase
' Crear instancia de clase Pen
Dim pen As New Pen ()
' Establecer valor
de lápiz . Color = 1
' Obtener valor
Dim color como Int32 = pen . Color
Visual Basic 6
' en una clase llamada clsPen
Private m_Color As Long
Propiedad pública Obtener color () Mientras Color = m_Color Fin de la propiedad
Propiedad pública Let Color ( ByVal RHS As Long ) m_Color = RHS Fin de la propiedad
'accediendo:
Dim pen As New clsPen ' ... pen . Color = No pen . Color
Véase también
- Atributo (informática)
- Propiedad limitada
- Campo (ciencia informática)
- Indexador (programación)
- Método (programación informática)
- Método mutador
- Principio de acceso uniforme
Referencias
- ^ "Accessors And Mutators In Java" (Accesores y mutadores en Java). C# Corner - Comunidad de desarrolladores de software y datos . Consultado el 5 de enero de 2022 .
- ^ "Portabilidad de propiedades nativas de C++". Desbordamiento de pila . Desbordamiento de pila . Consultado el 5 de enero de 2022 .
- ^ "propiedad (C++)". Documentación técnica de Microsoft . Microsoft . Consultado el 5 de enero de 2022 .
- ^ "clang::MSPropertyDecl Class Reference". Clang: una interfaz de usuario de la familia de lenguajes C para LLVM . Consultado el 5 de enero de 2022 .
- ^ "Extensión de palabra clave __property". Documentación Wiki de Embarcadero/IDERA . Consultado el 5 de enero de 2022 .