Convenciones para métodos de acceso (getters y setters) en C++
Se han hecho varias preguntas sobre los métodos de acceso en C++, pero ninguna fue capaz de satisfacer mi curiosidad sobre el tema.
Trato de evitar los accesores siempre que sea posible, porque, como Stroustrup y otros programadores famosos, considero una clase con muchos de ellos un signo de mal OO. En C++, en la mayoría de los casos puedo agregar más responsabilidad a una clase o usar la palabra clave amigo para evitarlas. Sin embargo, en algunos casos, realmente necesita acceso a miembros específicos de la clase.
Hay varias posibilidades:
1. No use accesores en absoluto
Solo podemos hacer públicas las variables de miembro respectivas. Esto es un no-go en Java, pero parece estar bien con la comunidad de C++. Sin embargo, estoy un poco preocupado por los casos en los que se debe devolver una copia explícita o una referencia de solo lectura (const) a un objeto, ¿es exagerado?
2. Use métodos get/set al estilo Java
No estoy seguro de si es de Java en absoluto, pero quiero decir esto:
int getAmount(); // Returns the amount
void setAmount(int amount); // Sets the amount
3. Use los métodos get/set de objective C-style
Esto es un poco raro, pero aparentemente cada vez más común:
int amount(); // Returns the amount
void amount(int amount); // Sets the amount
Para que eso funcione, tendrá que encontrar un nombre diferente para su variable miembro. Algunas personas añaden un subrayado, otras anteponen "m_". A mí tampoco me gusta.
¿Qué estilo usas y por qué?
9 answers
Desde mi perspectiva como sentado con 4 millones de líneas de código C++ (y eso es solo un proyecto) desde una perspectiva de mantenimiento yo diría:
Está bien no usar getters / setters si los miembros son inmutables (es decir,
const
) o simples sin dependencias (como una clase de puntos con miembros X e Y).Si el miembro es
private
solamente, también está bien omitir getters/setters. También cuento los miembros de interno pimpl-clases comoprivate
si el .unidad cpp es pequeñito.Si el miembro es
public
oprotected
(protected
es tan malo comopublic
) y no-const
, no simples o tiene dependencias, a continuación, utilice los métodos getter/setter.
Como chico de mantenimiento mi principal razón para querer tener getters/setters es porque entonces tengo un lugar para poner puntos de interrupción / registro / algo más.
Prefiero el estilo de la alternativa 2. como eso es más buscable (un componente clave en la escritura de código mantenible).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-24 12:41:01
-
Nunca uso este estilo. Porque puede limitar el futuro del diseño de tu clase y los geters o setters explícitos son igual de eficientes con un buen compilador.
Por supuesto, en realidad los getters o setters explícitos en línea crean la misma dependencia subyacente en la implementación de la clase. Solo reducen la dependencia semántica. Todavía tienes que recompilar todo si los cambias.
Este es mi estilo predeterminado cuando uso accessor método.
Este estilo me parece demasiado "inteligente". Lo uso en raras ocasiones, pero solo en casos en los que realmente quiero que el accessor se sienta tanto como sea posible como una variable.
Creo que hay un caso para bolsas simples de variables con posiblemente un constructor para asegurarse de que todos están inicializados a algo cuerdo. Cuando hago esto, simplemente lo hago un struct
y lo dejo todo público.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-05 19:45:42
2) es la mejor OMI, porque hace que sus intenciones más claras. set_amount(10)
es más significativo que amount(10)
, y como un buen efecto secundario permite a un miembro llamado amount
.
Variables públicas es generalmente una mala idea, porque no hay encapsulación. Supongamos que necesita actualizar una caché o actualizar una ventana cuando se actualiza una variable? Lástima si tus variables son públicas. Si tiene un método establecido, puede agregarlo allí.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-05 19:58:36
Ese es un buen estilo si solo queremos representar
pure
datos.No me gusta :) porque
get_/set_
es realmente innecesario cuando podemos sobrecargarlos en C++.STL utiliza este estilo, como
std::streamString::str
ystd::ios_base::flags
, excepto cuando se debe evitar! ¿Cuando? Cuando el nombre del método entra en conflicto con el nombre de otro tipo, se usa el estiloget_/set_
, comostd::string::get_allocator
debido astd::allocator
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-06 01:49:56
En general, siento que no es una buena idea tener demasiados getters y setters siendo utilizados por demasiadas entidades en el sistema. Es solo una indicación de un mal diseño o encapsulación incorrecta.
Dicho esto, si tal diseño necesita ser refactorizado, y el código fuente está disponible, preferiría usar el patrón de Diseño del visitante. La razón es:
A. Le da a una clase la oportunidad de decidir a quién permitir el acceso a su estado privado
B. Da una clase an oportunidad de decidir qué acceso a permitir a cada una de las entidades que son interesado en su estado privado
C. It documenta claramente tal acceso externo a través de una interfaz de clase clara
La idea básica es:
A) Rediseñar si es posible,
B) Refactor tal que
Todo acceso al estado de clase es a través de un bien conocido individualista interfaz
It debería ser posible configurar algún tipo de hacer y no hacer a cada una de estas interfaces, por ejemplo, todas acceso desde entidad externa BUENO debe ser permitido, todo el acceso desde entidad externa MAL debe ser no permitido, y entidad externa OK se debe permitir obtener pero no establecer (por ejemplo)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-06 02:32:29
No excluiría el uso de los accesores. Puede que para algunas estructuras POD, pero los considero una buena cosa (algunos accesores podrían tener lógica adicional, también).
Realmente no importa la convención de nomenclatura, si usted es consistente en su código. Si está utilizando varias bibliotecas de terceros, es posible que usen diferentes convenciones de nomenclatura de todos modos. Así que es una cuestión de gustos.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-05 19:34:36
He visto la idealización de clases en lugar de tipos integrales para referirse a datos significativos.
Algo como esto a continuación generalmente no está haciendo un buen uso de las propiedades de C++:
struct particle {
float mass;
float acceleration;
float velocity;
} p;
¿Por qué? Porque el resultado de p. masa*p. aceleración es un flotador y no una fuerza como se esperaba.
La definición de clases para designar un propósito (incluso si es un valor, como amount mencionado anteriormente) tiene más sentido, y nos permite hacer algo como:
struct amount
{
int value;
amount() : value( 0 ) {}
amount( int value0 ) : value( value0 ) {}
operator int()& { return value; }
operator int()const& { return value; }
amount& operator = ( int const newvalue )
{
value = newvalue;
return *this;
}
};
Usted puede acceder al valor en cantidad implícitamente por el operador int. Además:
struct wage
{
amount balance;
operator amount()& { return balance; }
operator amount()const& { return balance; }
wage& operator = ( amount const& newbalance )
{
balance = newbalance;
return *this;
}
};
Uso de Getter/Setter:
void wage_test()
{
wage worker;
(amount&)worker = 100; // if you like this, can remove = operator
worker = amount(105); // an alternative if the first one is too weird
int value = (amount)worker; // getting amount is more clear
}
Este es un enfoque diferente, no significa que sea bueno o malo, sino diferente.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-20 21:36:47
Permítanme hablarles de una posibilidad adicional, que parece la más conscrita.
Necesita leer y modificar
Simplemente declare esa variable pública:
class Worker {
public:
int wage = 5000;
}
worker.wage = 8000;
cout << worker.wage << endl;
Basta con leer
class Worker {
int _wage = 5000;
public:
inline int wage() {
return _wage;
}
}
worker.wage = 8000; // error !!
cout << worker.wage() << endl;
La desventaja de este enfoque es que necesita cambiar todo el código de llamada (agregar paréntesis, es decir) cuando desea cambiar el patrón de acceso.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-15 12:51:52
Una posibilidad adicional podría ser :
int& amount();
No estoy seguro de recomendarlo, pero tiene la ventaja de que la notación inusual puede evitar que los usuarios modifiquen los datos.
str.length() = 5; // Ok string is a very bad example :)
A veces es tal vez solo la buena elección a hacer:
image(point) = 255;
Otra posibilidad de nuevo, utilice la notación funcional para modificar el objeto.
edit::change_amount(obj, val)
De esta manera la función dangerous/editing se puede extraer en un espacio de nombres separado con su propia documentación. Este parece venga naturalmente con la programación genérica.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-11 14:06:39