2010-10-14 19 views
9

haciendo esta pregunta porque siento que las variables miembro de mi base se necesitarán más tarde en las clases derivadas. ¿Hay un inconveniente de protegerlos?¿Es una buena práctica proteger las variables miembro?

EDITAR: Editado para mostrar mejor mi intención.

EDITAR: @sbi: ¿Esto también está mal?

Esta clase se utilizará para la grabación de errores y recuperación en otras clases. ¿Es mejor derivar de ella o usar un objeto de ella? No lo sé. Pero creo que los métodos get y setter son de lo que se trata esta clase.

class ErrorLogger 
{ 
    public: 
     //Making this function virtual is optional 
     virtual void SetError(const char*, ...); 
     const char* GetError() const; 
    protected: 
     char* z_ErrorBuf; 
}; 
+1

¿Por qué crees que las variables miembro se necesitarán más adelante en las clases derivadas? ¿Para qué se necesitarán y por qué necesitarán estar expuestos? –

Respuesta

21

La encapsulación es una de las principales características de OO. Encapsular sus datos en clases significa que los usuarios de la clase no pueden romper las invariantes de datos de la clase, porque el estado de clase solo se puede manipular a través de sus funciones miembro.

Si permite el acceso derivada clases a su clase base de datos, entonces clases derivadas tienen que tener cuidado para no invalidar la clase base invariantes de datos. Eso arroja la encapsulación fuera de la ventana y está simplemente mal. (Lo mismo ocurre con getters and setters, BTW.)

Cada vez me encuentro utilizando menos protected, incluso para funciones de miembros. Si una clase implementa completamente un concepto simple, entonces todo su estado debe ser manipulable a través de su interfaz pública. Si las clases derivadas necesitan "puertas traseras" para colarse, entonces normalmente cuestiono mi diseño.(Lo cual no quiere decir que nunca use protected. Solo encuentro que lo necesito cada vez menos)

+0

Y de todos modos siempre debe crear variables como privadas y usar propiedades/accesos protegidos. –

+2

@SoMoS: Mire el documento vinculado sobre los setters y getters. Ellos son una abominación. – sbi

+1

@SoMoS: No estoy de acuerdo 107%. Una arquitectura que usa getters y setters simples para acceder a una variable es una tontería. Solo haz que las malditas cosas sean públicas. ¿Cual es la diferencia? –

2

Tengo curiosidad de lo que otras personas responderán a eso.

Así como para el paradigma descriptores de acceso, es posible declarar su uso privado y protegido métodos getter y setter. Si la implementación de su clase base cambia, solo tiene esos getter y setter para modificar.

2

Si crees que las clases secundarias necesitarán acceder a esas variables más tarde, entonces sí, protegerlas.

No hay inconveniente, siempre y cuando se cumple la condición antes mencionada.

Si usted quiere tomar el paso adicional y proteger sus variables de acceso desde el exterior, siempre se puede crear variables miembro privadas y luego usar métodos protegidos para acceder/modificar esas variables privadas.

2

Heredar es solo otra forma de usar una clase. Está más acoplado y al hacer que las variables de sus miembros estén protegidas, se acoplarán aún más, por lo que no debería cambiarlas sin conocer el impacto en cada clase heredada. Si es su clase base y sus clases heredadas, probablemente no habrá ningún daño, pero usted pierde el control de cómo se debe acceder a los miembros (bloqueo, registro, lectura/escritura, persistencia, ...).

0

Su diseño de clase general le mostrará si terminará con miembros protegidos o no. Ya sea que los haga privados, protegidos o públicos, eso no es algo cincelado en la piedra, así que siéntase libre de crear su árbol de clase sin pensar demasiado en eso. Si al principio no sabe si el miembro se utilizará por clase derivada, y de qué manera, seguramente se enterará al codificar.

Lo más importante es decidir lo que es público vs/privada, porque esa es la forma de presentar su clase con el mundo exterior.

1

Los datos protegidos tienen todos los inconvenientes de los datos públicos, por lo que también podría hacerlos públicos.

1

Si los vuelve privados y luego decide que deben ser accesibles para las clases derivadas, puede cambiarlos para protegerlos sin afectar a ningún código que dependa de esa clase. También tiene la opción de agregar accesos protegidos.

Si los proteges y luego decides que deben ser privados, cambiarlos podría romper el código existente que depende de que estén disponibles.

Mi regla de oro personal es hacer todo privado y promocionarlos en la cadena de visibilidad según sea necesario.

1

Siempre que no haya intencionalmente diseñe la clase que se heredará a partir de entonces, no hay una manera confiable de adivinar qué métodos deben ser virtuales y qué miembros deben protegerse. Lo único de lo que puede estar seguro es que muy probablemente adivine mal.

No pierda el tiempo con esto, use la palabra clave sellada y haga que los miembros sean privados. Siempre puedes refactorizar más tarde, deberás hacerlo de todos modos.

+1

El estándar C++ no tiene la palabra clave 'sealed'. –

+0

Vaya, etiqueta incorrecta. Bueno, la misma idea pero menos * sellada *. –

+0

@downvoter - no me culpen por el idioma que falta la palabra clave. –

-1

Proporcione un getter protegido y quizás setter a la variable interna privada, es un poco más de código, pero es mucho más limpio.

0

No haces que los miembros sean públicos por algún motivo. Incluso si esos miembros se pueden configurar o obtener libremente. Proporciona facilitadores públicos falsos y getters. POR EXACTAMENTE LA MISMA RAZÓN, NO debes hacer que los miembros estén protegidos. En su lugar, debe proporcionar setters y getters protegidos. La simetría es muy fuerte.

+1

No estoy de acuerdo. Vea el comentario en la publicación de sbi –

+1

@John: Incluso puedo entender por qué no está de acuerdo. Pero mi punto aquí es "SI" es malo tener miembros públicos, "ENTONCES" es malo tener miembros protegidos. Pero, de hecho, la prohibición categórica para los miembros públicos es discutible. –

+0

Ah, ya veo lo que estás diciendo ahora. –

1

Hacer algo 'público' crea un contrato que será vinculante para todas las clases heredadas. Hacer algo 'protegido' crea un contrato con directamente-clases heredadas, pero no obliga a las clases a hacer que dicho contrato esté disponible para ninguno de sus descendientes.

Si uno espera que el código fuente de una clase base esté disponible para cualquiera que herede de él, y espera que la clase base nunca cambie (normalmente esto significa que la razón para usar la clase base es permitir miembros públicos y propiedades de la clase base para usar indistintamente con clases derivadas, en lugar de reducir la cantidad de código necesario para las clases derivadas) y si todos los métodos públicos son virtuales o están directamente relacionados con los métodos virtuales, no hay mucha desventaja para utilizando campos protegidos en lugar de getters/setters virtuales protegidos. Si una clase descendiente necesita cambiar la forma en que se usan los campos, simplemente puede anular todos los métodos que los usan.

Si se espera que las clases derivadas se puedan crear en situaciones donde las clases superiores a ellas en la jerarquía no se conocen completamente o no son inmutables, entonces puede ser más apropiado tener getters/setters protegidos, pero esa responsabilidad podría ser izquierda con quien crea las capas "opacas" en la jerarquía.

Ejemplo: una colección puede mantener un campo llamado 'conteo'. Una versión base de la colección puede almacenar cosas de manera que sea fácil mantener un campo que siempre contenga la cantidad de elementos, pero una versión derivada puede almacenar cosas de una manera que lo haga difícil. Al tener un campo llamado "recuento", la clase base promete a sus descendientes directos que mantendrá la cantidad de elementos en ese campo. Una clase derivada podría almacenar las cosas de manera diferente, de modo que un campo de "conteo" no era significativo.Tal clase podría sombrear el campo de conteo con una propiedad de solo lectura; sus descendientes sabrían que tenían que leer una propiedad, mientras que los descendientes de la clase original sabrían que podían leer un campo.

El punto más importante es que las cosas protegidas en una clase sólo crean un contrato con descendientes directos, y los descendientes pueden decidir si debe o no hacer un contrato similar disponible para los sub-descendientes.

Addendum: lo único que se gana al agregar objetos de protección y modificadores virtuales protegidos es la capacidad de las clases derivadas de cambiar cómo el código de clase base accede a los campos/propiedades. Algunas veces esto será necesario, pero más a menudo creará problemas. Por ejemplo, si una colección puede eliminar frecuentemente elementos recientemente agregados, una clase derivada puede envolver cosas para que los últimos artículos agregados se guarden en una pequeña colección "adicional" y se transfieran a la colección principal después de que se agreguen elementos adicionales suficientes. El código para la colección principal esperará su propio campo de "conteo" para indicar cuántos elementos hay en la colección principal. Si una clase descendiente anula la propiedad "conteo" para incluir sus propios elementos, el código principal se romperá. La clase descendiente debería en su lugar sombra el campo de conteo para que sus descendientes verán un recuento que incluye los elementos de bonificación, pero la clase base aún verá el recuento que solo incluye sus propios elementos.

2

Personalmente, suelo intentar restringir el uso de protected a cosas.

Considero cualquier otro uso de protected como conceptualmente equivalente a public. En el sentido de que si escribe un método no virtual protegido, escríbalo como si fuera público. Lo mismo para un campo. Si el campo rompería algo si fuera público, también romperá algo si está protegido.

No significa que sea malo tener un campo protegido o un método no virtual, solo significa que debe ser cuidadoso y deliberado con su uso, y saber que alguien, en algún lugar, puede usar esas cosas y potencialmente romper tu clase simplemente derivandolo.

+0

En mi humilde opinión, protegido virtual a veces es apropiado, pero el sombreado a menudo es más apropiado que anular. Ver el apéndice a mi respuesta. – supercat

Cuestiones relacionadas