2011-08-04 14 views
7

Soy relativamente nuevo en C++ y creo que mi pregunta puede entenderse mejor con el ejemplo. En mi archivo de cabecera, supongamos que tengoC++ Getters-Setters en el archivo de implementación

class myClass{ 
    public: 
     double getVar1(); 
     void setVar1(double newVar1); 
     void copyVar1(myClass* dat); 

    private: 
     double var1; 
}; 

en mi archivo .cc aplicación, al aplicar el método copyVar1, debo hacer

void myClass::copyVar1(myClass* dat){ 
    var1 = dat->var1; 
} 

o

void myClass::copyVar1(myClass* dat){ 
    var1 = dat->getVar1(); 
} 

donde en el segundo caso, utilizo el método getter en su lugar. Ambos funcionan correctamente en Visual C++, pero me gustaría saber cuál es mejor usar en la práctica.

¡Gracias por sus comentarios!

+1

También vea [Son funciones get y set populares entre los programadores C++] (http://stackoverflow.com/questions/737409/are-get-and-set-functions-popular-with-c-programmers) –

Respuesta

4

¿Mejores prácticas? Sobrecargue el operador de asignación en lugar de escribir un método.

myClass & myClass::operator=(const myClass & dat) 
{ 
    var1 = dat.var1; // or dat.getVar1() 
    return *this; 
} 

En cuanto a usar el campo o llamar a un colocador ... Es todo una cuestión de gusto personal. Si su captador tiene algún efecto secundario, entonces probablemente debería llamarlo, de lo contrario, use el campo.

Entonces, un gran "depende".

+1

Pero si la clase tenía más de un miembro, la asignación no funcionaría, ya que debería copiar todos los valores, no solo uno. – Skizz

+0

@Skizz De hecho, pero ese ejemplo tiene solo un campo. –

+1

El uso del * getter * centraliza la operación en una ubicación. Esto es un beneficio para el mantenimiento y la depuración. El compilador debe ser lo suficientemente inteligente como para alinear el captador; de lo contrario, haga getters y setters en línea para ayudar a la optimización del compilador. –

0

Depende. Mucha gente le dirá que el uso de getters/setters en lugar de las variables es más robusto a los errores y cambios de programación y reduce la duplicación del código. Pero mientras estos getters/setters no tengan funciones en línea, es posible que obtengas un pequeño golpe de rendimiento y, como la implementación debe conocer los componentes internos de la clase, ¿por qué no utilizar las variables directamente?

1

yo preferiría el uso de fijadores y getter de esa manera si su cambio de forma en algunos detalles de implementación (por ejemplo, introducir la validación en el valor de asignación) se broma que tienen que cambiar en un solo lugar en la moda ...

+0

A veces un getter no tiene una variable de miembro coincidente, pero se calcula de alguna manera en su lugar. En esas situaciones, obviamente necesita usar la variable directamente. No hay una respuesta definitiva en absoluto: siempre depende de lo que represente la variable/getter. – ereOn

+0

@ereOn - sí, depende ... –

0

¿Estás tratando escribir un constructor de copia? ¿Por qué necesita copyVar1 cuando tiene un setVar1? Si intenta escribir un constructor de copia, es mejor no usar getter.

myclass(const myclass& other) 
{ 
var1 = other.var1; 
} 

Cuando tiene get y set, por qué no hacer que el público var1?

+0

Es incluso mejor utilizar listas de inicializadores en constructores, en lugar de asignación. –

+0

Fue solo un ejemplo simple. Hay más en el método copyVar1 que actualmente tengo implementado. –

+0

@ A-A: lo que quiere es ** copia-asignación **. 'myclass & operator = (const myclass & other);' Mira la solución @Etienne. – Mahesh

2

Casi siempre debe utilizar los métodos getter/setter para acceder a una variable cuando está fuera de la clase, y con frecuencia debe hacerlo porque esa es la única forma de hacerlo. Sin embargo, cuando estás dentro de la clase puedes usar cualquiera, y si el método getter no hace más que devolver la variable, no hará la diferencia.

Su decisión va a ser sobre la base de si tiene código en el método getter que hace algo más que devolver la variable, y si desea que el código que se ejecuta cuando se llama copyVar1. Si no lo sabe, mi consejo sería seguir utilizando el método getter si alguna vez decide cambiar el código en el futuro. Si bien funciona bien ahora solo accediendo directamente a él, y es posible que tenga un rendimiento microscópicamente mejor, será mucho más fácil encontrar un error al llamar al captador cuando no debería, que no lo llame cuando debería. Y el compilador probablemente terminará optimizando lo suficiente como para que usted ni siquiera sienta la diferencia. : D

+1

La mayoría de los compiladores alinearían el getter de todos modos, por lo que el rendimiento no es el problema aquí. –

0

No hay forma correcta o incorrecta de hacerlo aquí.

Sin embargo, está asumiendo que getVar1() devuelve el valor o var1. Si decide cambiar la forma en que se almacena el valor de var1, entonces necesita revisar todo el código y actualizarlo. Usar un setter/getter reduce esto a solo un par de métodos. En cuyo caso, se debe utilizar una tercera opción:

void myClass::copyVar1(myClass* dat){ 
    setVar1 (dat->getVar1()); 
} 

y entonces eliminar por completo la dependencia de var1, puede cambiar a otra cosa var1 y la copyVar1 seguirá funcionando.

0

Como dices, ambos funcionan correctamente y son perfectamente legales.

En cierto sentido, la diferencia entre acceder directamente a la variable de miembro o utilizar un descriptor de acceso es que define una "capa" más fuerte dentro de su clase; esta capa, como cualquier capa, te ayuda a reducir las dependencias.

En otras palabras, un método getter responde básicamente al requisito de no divulgar al mundo exterior un detalle de implementación; por ejemplo, puede decidir que un día, en lugar de almacenar var1 como un doble, lo calcule. Por lo tanto, el descriptor de acceso le brinda este tipo de libertad: hasta cierto punto, puede cambiar la implementación sin afectar otras clases (es decir, reducir dependencias).

Lo mismo es cierto en el caso de usar el método getter dentro de la clase en sí, es decir, está eliminando dependencias dentro del alcance de la clase y su diseño es más resistente a los cambios.

0

El objetivo de la abstracción de los establecedores y captadores es que el método de recuperación puede cambiar. Cuando accede directamente a la variable miembro, si algo cambia, debe actualizar su uso en todas partes. Pero si usa la función, entonces cambiar la forma en que se recupera la variable solo tiene que cambiar en la función.

Ahora, porque esta es la misma clase, es mucho menos preocupante que cuando hace que las variables sean públicas, porque solo tiene que actualizar este archivo de implementación (en lugar de actualizar a cada usuario de su clase, que puede no ser posible si tienes una clase de biblioteca).

Para ver esto, consulte una clase que de repente debe ser segura para subprocesos. Ahora, la copiadora se vería

void myClass::copyVar1(myClass * dat) 
{ 
    scoped_lock lock(mutex); 
    var1 = dat->getVar1(); 
} 

y no tendría que fijar en otro sitio si siempre llamado por función. Si ha accedido a la variable directamente, entonces se vería como

void myClass::copyVar1(myClass * dat) 
{ 
    scoped_lock lock(mutex); 
    scoped_lock lock2(dat->mutex) 
    var1 = dat->var1; 
} 

que bloquea "dat" s mutex externa a dat, por lo general no se considera un muy buen diseño (si se hacen los ingenieros tienen que recordar para bloquear los objetos de otras personas luego abres la posibilidad de que olviden y no lo hagan).

Del mismo modo, si la variable comenzara a almacenarse en una base de datos, tendría que manejar eso también. O si la variable ahora se almacenó en dos variables diferentes y se construyó cuando se recuperó, puede ver cómo aumentaría la complejidad.

Pero recuerde, la filosofía de diseño del uso de accessors y mutators es reducir la complejidad potencial a través de la encapsulación. Hay ocasiones en las que se trabaja en proyectos más pequeños (especialmente proyectos personales) en los que no se tiene la intención de cambiar alguna vez la clase. Puede ser menos complejo acceder a ellos directamente. No tengas miedo de hacerlo, solo debes saber por qué estás tomando la decisión.

+0

Tenga en cuenta también que no debe usar constructores de copias u operadores de asignación para lo mismo que los mutadores: deben usarse en lugares diferentes. La copia y la asignación se utilizan cuando desea tener otro objeto como el que desea. Los mutadores se usan cuando se quiere poder modificar el comportamiento de una manera particular, sin modificar el resto del objeto. Usted solo escribe mutadores si hay otro estado que no cambiará. La forma de su mutador (que toma el estado de otro objeto existente) no debe implicar que deba ser una tarea o una copia. – ex0du5

Cuestiones relacionadas