2009-04-07 31 views
6

¿Es apropiado acceder a los miembros privados de una clase colocándolo en un puntero de vacío y luego en una estructura?Accediendo a miembros privados

No creo que tenga permiso para modificar la clase que contiene los miembros de datos a los que necesito acceder. No quiero arriesgarme a acceder a los miembros de los datos de forma indirecta si no es ético.

EDIT: Tuve que editar esto más ... Estoy bastante seguro de que la clase no se modificaría, por lo que está bien en ese sentido ... mi única preocupación es, si la persona que codificó esa clase llega a saber de esta, podría no ir bien con él :(

+0

¿Qué estás tratando de lograr específicamente al hacer esto? –

Respuesta

6

"Nunca digas nunca". Estoy seguro de que en algún lugar del universo, hay una situación que te obligará a tener que hacer esto ...

Pero ciertamente me encogería si tuviera que hacerlo. Realmente necesita obtener muchas opiniones sobre su situación antes de apretar el gatillo. ¿Puedes describir tu situación específica y tal vez podríamos ver si tiene sentido o qué mejores alternativas podrían existir?

En respuesta al comentario/pregunta-- ¿Definir "permisos" - permiso institucional? Eso suena no como un problema de programación, sino como algo para hablar con quien sea que afirme dicho permiso. Tal vez esto es más un problema político que uno técnico? De nuevo, creo que necesitamos más detalles, incluso si se trata de la política de la situación. Sin embargo, eso puede o no considerarse fuera del alcance del sitio web.

+0

Creo que lo he mencionado en la pregunta ... No tengo acceso a esa definición, pero necesito un miembro definido en esa clase para calcular algún valor. – Shree

+2

deseche esa clase y use una clase que proporcione acceso al miembro. –

+0

Esa sería otra clase. No tendrá acceso al miembro deseado. – southerton

26

no estoy seguro de que la "ética" realmente entrar en ella se revienta a los diablos de encapsulación aunque

EDIT:... casi lo haría nunca acepte esto si estuviera realizando una revisión de código. Tendría que trabajar realmente difícil de convencerme de que no hay forma de diseñar la necesidad de esto. Es posible que tenga éxito Eed, pero tendría que haber advertencias importantes en todo el lugar, y pruebas de unidad de rock duro para asegurarse de que si algo cambiaba para romperlo, lo sabría rápidamente.

+0

eso es cierto, pero si no tienes otra manera de hacerlo, ¿uno tiene que dejar ir ciertos conceptos? – Shree

+0

La encapsulación no está realmente allí para proteger del abuso. A veces, este es el único camino a seguir :-( –

+0

Si se trata de una clase de personas que está violando, entonces hay preocupaciones éticas más importantes :-) – veefu

3

Es ético, pero por lo general es un código sucio que se ve muy cerca, con un comportamiento indefinido y falta de transporte. Hazlo solo si es absolutamente necesario.

+0

Las personas son muy liberales (léase 'perezoso') al determinar dónde se encuentra la línea "absolutamente necesario". –

+0

Es cierto, y esto lleva a una serie de preguntas de entrevista simples pero interesantes que ayudan a contratar solo a las personas con el grado necesario de pereza. – sharptooth

+0

Sí. Tanto para el entrevistador como para el candidato. –

9

No. Lo que estás haciendo es Pure Evil.

+0

Oye, robaste mis etiquetas invisibles de http://stackoverflow.com/questions/722350/should-your-opensource-project-attempt-to-mimic-commercial-products. – chaos

+0

¡Pensé que las etiquetas invisibles eran de código abierto! –

5

Si usted siente la necesidad de hacer esto, se olvide de fundición - acaba de modificar la declaración de clase en el archivo de cabecera:

class A { 
    private: 
    int x; 
}; 

cambio que a:

class A { 
    public: 
    int x; 
}; 

y que son buenos para ir . Bueno, quizás "bueno" no es la palabra correcta.

+0

por qué no mencionar que viola la ODR. también va de no POD a POD. Me imagino que las posibilidades son mejores, entonces algo se rompe. tal como está, uno podría leer su respuesta como "usted puede hacer ... funcionará" –

+0

Recuerde que mientras juega a la ruleta rusa, una vez cada tanto la bala dispara. –

+0

Solo rompe el ODR si la definición de A está en una biblioteca. Y no estaba hablando en serio ... –

2

Ah, abstracción - No se puede vivir sin él y sin embargo es tan doloroso para hacer frente a veces :)

De todos modos, la ética a un lado, lo que si el "dueño" de la clase decide cambiar el interior implementación, o simplemente invierte el orden de los miembros de datos privados?

+0

Por lo general, solo es doloroso tratarlo si lo arruinas. –

+0

@John tan cierto! +1 –

1

Respuesta simple: No.

No es ético y que se convertirá en una pesadilla de mantenimiento en algún momento. Los miembros privados internos de una biblioteca pueden cambiar y romper su código.Los desarrolladores de la biblioteca no necesitan saber (ni querer) que está violando la encapsulación.

Las clases generalmente tienen invariantes sobre sus métodos que algunas veces no se documentarán, pero el acceso y el cambio de los valores desde el exterior pueden romper esas invariantes. Como ejemplo, si cambia el espacio reservado en un vector por un valor mayor, el vector no asignará espacio nuevo hasta que haya llenado el existente y eso no sucederá antes de golpear la memoria no asignada: su aplicación fallará.

Si el atributo es privado, no es para ti usarlo, solo para la clase en sí o los amigos de la clase que conocen sobre el miembro, cómo usarlo, cómo no romperlo. Si el programador quería que cambiaras el campo, sería público.

+0

Aceptado ... esta fue la razón por la que hice esta pregunta ... pero ¿hay alguna otra forma de acceder a los miembros? Al menos no puedo pensar en ningún ... – Shree

+0

Sin más información sobre el problema real, no puedo decirlo. Pero creo que tal vez quiera abordar su problema desde otra perspectiva con la información que tiene sobre la clase. –

27

No consideremos la ética por un momento. Consideremos el estándar.

Lo que está proponiendo hacer es no estándar. Ver la sección 9.2, cláusula 12 de la norma. "El orden de asignación de los miembros no estáticos separados por un especificador de acceso no está especificado". Por lo tanto, si tiene una clase con miembros privados y una estructura sin miembros privados, la norma no garantiza que los miembros estarán en el mismo orden.

Por lo tanto, si su truco funciona, solo funciona por accidente, que los escritores del compilador lo hicieron de esa manera. No hay garantía de que funcione en otro compilador, una versión posterior del mismo compilador o con diferentes diseños de clase.

Sin mencionar que, si no tiene autorización para modificar la clase (por ejemplo, para proporcionar una función de acceso simple), probablemente no tenga autorización para objetar si cambia cualquier detalle de implementación en la clase. (Una de las ideas detrás de lo público y lo privado es distinguir lo que se promete de lo que es libremente modificable). Por lo tanto, el diseño puede cambiar, o el miembro puede llegar a significar algo diferente, o eliminarse del todo.

Herb Sutter escribió a Guru of the Week columna en este tema.

¿En cuanto a la ética? Si realmente, realmente tienes que hacer algo como esto, y no puedes salir de él, documentalo muy cuidadosamente. Si sus estándares de codificación tienen algún tipo de procedimiento para marcar un comportamiento no estándar, úselos. Si no, tenga mucho cuidado de anotarlo de una manera que no se pase por alto cuando algo sale mal.

+0

Me gustó su opinión :) – Shree

+0

Muy buena referencia para GoTW. Volvería a votar nuevamente si pudiera. –

+0

Muchas gracias ... Estaba a punto de sacar mi copia del estándar y verificar la cláusula de asignaciones para obtener garantías. Muy buen trabajo de detective. –

6

Me sucedió esto porque existía un sistema de control de origen muy desagradable donde las versiones anteriores de la aplicación que realizaban cambios en los archivos de encabezado eran prácticamente imposibles.

En algunos casos, solo tiene que hacer un truco.

En el archivo de origen desde el que se necesita para acceder al miembro de datos privada que puede poner en esto como una primera línea:

#define private public 
#define protected public 

y accede a cualquier cosa que desee.

+0

Creo que debería intentarlo, pero de nuevo puede que no sea ético. Pero sí, como dijiste, en algunos casos es simplemente imposible modificar algún código. – Shree

1

El único problema "ético" es lo que le estás haciendo al pobre bastardo que va a tener que descubrir y mantener tu código.

Los miembros privados son solo eso. Él puede, y muy probablemente lo hará, un día cambiar a ese miembro. Cuando eso sucede, es posible que ni siquiera lo note, ya que es muy probable que todavía haya memoria allí, simplemente no el miembro que estaba esperando. Maldición cerca de cualquier cosa casi imposible que puedas imaginar, podría comenzar a suceder cuando tu código se ejecute. ¿Cómo alguien alguna vez podrá depurar eso?

12

Acabo de agregar un entry to my blog que muestra cómo se puede hacer de una manera completamente conforme. Aquí hay un ejemplo de cómo se utilice para la siguiente clase

struct A { 
private: 
    int member; 
}; 

Sólo declarar una etiqueta con su nombre y una instancia de un ladrón, como muestra el siguiente ejemplo (mi post muestra la implementación del ladrón). A continuación, puede acceder a ese miembro usando un puntero miembro de

struct Amem { typedef int type; }; 
template class rob<Amem, &A::member>; 

int main() { 
    A a; 
    a.*result<Amem>::ptr = 42; // Doh! 
} 

Pero en realidad, esto no demuestra que el C++ 's reglas de acceso no son confiables. Las reglas de idioma están diseñadas para proteger contra errores accidentales: si intenta robar datos de un objeto, el lenguaje by-design no le tomará mucho tiempo para evitarlo.


Lo anterior es una manera de acceder a miembros privados y protegidos de una manera conforme. Esta es otra manera de acceder a los miembros protegidos de forma estándar. La idea básica es utilizar un puntero de miembro

std::deque<int> &getAdapted(std::stack<int> &s) { 
    struct voyeur : stack<int> 
    { using stack<int>::c; }; 
    return s.*(&voyeur::c); 
} 

int main() { 
    std::stack<int> s; 
    std::deque<int> &adapted = getAdapted(s); 
    output(adapted); // print the stack... 
} 

No hay casting o tipo de juego de palabras involucrado. Toma un puntero a un miembro protegido de std::stack<int> a través de una clase derivada de él donde ese nombre de miembro es público, por lo que el compilador lo permite. Luego lo usa en un objeto std::stack<int>, que también está permitido.

0

Supongo que esta clase es parte del proyecto en el que está trabajando.

Hay un problema ético aquí: Si en su empresa ve la propiedad del código como sacrum. O peor, no se te permite modificar el código que no es tuyo. Sí. Puede herir la sensación de una persona que mantiene esa clase. O enojado con él si su salario está relacionado con su código. así que lo mejor es solo pedirle ayuda, y algunas sugerencias, por ejemplo. agrega la función getter o cambia de privado a público, todo en función de tu intuición de usar ese nuevo código.

Hack que ha mencionado es realmente la práctica de la cama. Si no se puede modificar ese código y el mantenedor no se cambiará nada. Considere usar el patrón de diseño del adaptador.

Cuestiones relacionadas