[C++] Get / Set en el mundo c ++, faux-pas?


Answers

La encapsulación es un concepto de OOP y se aplica a todos los lenguajes de OOP. Los miembros de datos públicos romperían la encapsulación. Esto puede estar bien si tiene un objeto muy simple que no necesita encapsulamiento, sin embargo esas situaciones son la excepción y una vez que toma la decisión puede ser difícil regresar y deshacerla.

Para la mayoría de los objetos, querrás tener getters y setters, pero siempre debes considerar cómo se usará realmente el objeto cuando los escribas. Boost y STL están llenos de getters y setters, simplemente no usan los nombres "get" y "set", sino que usan nombres como "length", "end", "reserve", "capacity", etc. La razón por la que no use las palabras get o set es porque estas funciones tienen un propósito mayor que el de establecer un valor en el objeto.

Tus getters y setters deberían hacer lo mismo. En lugar de diseñar la interfaz en términos de cómo funciona un objeto, debe definirlo en términos de cómo se usará.

Question

Observé que get / set no es el modo c ++ en lo que puedo decir mirando en boost / stl, e incluso leyendo las escrituras de algunos de los mejores expertos en c ++.

¿Alguien usa get / set en su diseño de clase de c ++, y alguien puede sugerir una regla empírica sobre dónde, si este paradigma pertenece en el mundo c ++?

Obviamente, es muy popular en Java e imitado por c # usando el azúcar sintáctico de la propiedad.

EDITAR:

Después de leer más sobre esto en uno de los enlaces proporcionados en la respuesta a continuación, encontré al menos un argumento para mantener los descriptores de acceso de un campo miembro con el mismo nombre que el campo de miembro. A saber, que simplemente podría exponer el campo miembro como público y, en su lugar, convertirlo en una instancia de una clase y luego sobrecargar al operador (). Al utilizar set / get, obligaría a los clientes a no solo a recompilar, sino también a cambiar su código.

No estoy seguro de que me encanta la idea, me parece un poco demasiado fina, pero hay más detalles aquí:

C ++ mató al Getter / Setter




Tiendo a tener getters y setters, simplemente no tiendo a llamarlos "getX and" setX ", generalmente haré algo como esto por ejemplo:

int x = o->x() // getter
o->setX(5); // setter

Me parece que tener el captador simplemente sea el nombre de la "propiedad" simplemente se lee mejor.




Incluso si c ++ no admite acceso a propiedades simulando, no solo mejoramos la legibilidad o proporcionamos encapsulamiento, sino que proporcionamos un mecanismo de control para establecer un valor a una variable u obtenemos un valor calculado para una variable. Este es el objetivo final de los usuarios. Para alcanzar estos objetivos, el idioma necesario necesariamente es compatible con los usuarios directamente. Período.




Voy a tomar algunas conjeturas.

  • C ni siquiera tenía la posibilidad de getters / setters, por lo que había una costumbre de usar acceso directo a los miembros, como en una estructura. El hábito atrapado en C ++.
  • C / C ++ siempre ha favorecido la velocidad, y si hubiera alguna posibilidad de que un viejo compilador no se alineara correctamente, un getter / setter tendría una penalización de velocidad.

Ninguno de estos son razones convincentes.




Va a ser un poco didáctico aquí ...

Hay dos aspectos para los usuarios:

  • Trabajando dentro de la sintaxis del lenguaje
  • Intento de comunicación

También hay un tercer aspecto que a menudo se ignora, y que tiene que ver con el manejo del cambio con gracia. Mi artículo que enlazas para abordar este último punto, pero no te dice nada sobre los otros dos.

Intentar manejar el cambio dentro de la sintaxis del idioma que está utilizando es principalmente un problema técnico, que es susceptible de algunos consejos reunidos en una página web con un poco de código para respaldarlo.

El aspecto más difícil es comunicar la intención y la forma de hacerlo es seguir con las expresiones idiomáticas del idioma. Desafortunadamente en C ++ la sintaxis se interpone en el camino de este modo, así que tenemos cosas como .size () en las colecciones y .first y .second en los pares. Todos son accesadores, pero la sintaxis cambia dependiendo de la implementación - ouch.

Ahora, eJames habla de miembros públicos rompiendo la encapsulación. Si un miembro es público o no, no tiene nada que ver con la encapsulación. La encapsulación es un producto del diseño de los objetos y de los controles disponibles para el diseñador de la clase dentro del lenguaje que está utilizando. Esto es algo que exploré con más profundidad en "Encapsulation is a Good Thing ™" (este sitio no me deja agregar un enlace todavía, pero supongo que no es demasiado difícil para Google).

Lo que nos deja es que en C ++ un atributo derivado debe usar la sintaxis de invocación del método. Un campo no derivado no tiene que serlo, pero puede elegir si así lo desea. Si utiliza la sintaxis de invocación del método, debe escribir usted mismo el método de envoltura. No es difícil, pero sin duda se suma al conteo de líneas. Lo que traté de mostrar fue una forma de usar el lenguaje de plantilla de C ++ para abstraer el código de acceso. No es totalmente exitoso, pero maneja muchos casos de uso.

En cuanto a si deberíamos usar accesores o no, el problema es que la sintaxis de C ++ obliga a la distinción entre acceso de miembro simple y acceso a métodos como desarrolladores. Esto es molesto, pero tenemos algunas herramientas para hacer algo al respecto.

Como desarrollador de bibliotecas, he descubierto que usar siempre la sintaxis de invocación de métodos me ayuda a crear API más robustas, porque si encuentro que quiero reemplazar un miembro simple con algo más complejo, entonces me da más opciones que no requieren bastante mucha sintaxis Recuerda, podría abstraer para el otro lado y hacer que una "función" parezca un valor mediante el uso adecuado de los operadores de reparto y operadores de asignación, tal vez lo intente y vea cómo me siento al respecto :)




En general, los métodos get / set subvierten la encapsulación al exponer la implementación interna y el estado. Si se encuentra utilizando get / set en cada pieza de datos en su clase, lo más probable es que sea simplemente un tipo agregado simple con solo datos públicos y sin métodos.

Realmente no compro que get / set hace que sea más fácil hacer cosas como, por ejemplo, hacer que tu clase sea segura para los subprocesos, porque la sincronización limitada que puedes proporcionar protege contra todos los tipos incorrectos de condiciones de carrera.