¿Puedo acceder a miembros privados desde fuera de la clase sin utilizar amigos?

Resuelto Jason Baker asked hace 15 años • 27 respuestas

Descargo de responsabilidad

Sí, soy plenamente consciente de que lo que estoy preguntando es totalmente estúpido y que cualquiera que desee intentar algo así en código de producción debería ser despedido y/o fusilado. Principalmente estoy mirando para ver si se puede hacer.

Ahora que eso está fuera del camino, ¿hay alguna forma de acceder a miembros de una clase privada en C++ desde fuera de la clase? Por ejemplo, ¿hay alguna forma de hacer esto con compensaciones de puntero?

(Se aceptan técnicas ingenuas y que no estén listas para producción)

Actualizar

Como se indicó en los comentarios, hice esta pregunta porque quería escribir una publicación de blog sobre la sobreencapsulación (y cómo afecta a TDD). Quería ver si había una manera de decir "usar variables privadas no es una forma 100% confiable de imponer la encapsulación, incluso en C++". Al final, decidí centrarme más en cómo resolver el problema que en por qué es un problema, por lo que no presenté algunas de las cosas mencionadas aquí de manera tan destacada como había planeado, pero aún así dejé un enlace.

En cualquier caso, si alguien está interesado en cómo salió, aquí está: Enemies of Test Driven Development parte I: encapsulación (sugiero leerlo antes de que decidas que estoy loco).

Jason Baker avatar Jan 08 '09 19:01 Jason Baker
Aceptado

Si la clase contiene funciones miembro de plantilla, puede especializar esa función miembro para satisfacer sus necesidades. Incluso si el desarrollador original no lo pensó.

seguro.h

class safe
{
    int money;

public:
    safe()
     : money(1000000)
    {
    }

    template <typename T>
    void backdoor()
    {
        // Do some stuff.
    }
};

principal.cpp:

#include <safe.h>
#include <iostream>

class key;

template <>
void safe::backdoor<key>()
{
    // My specialization.
    money -= 100000;
    std::cout << money << "\n";
}

int main()
{
    safe s;
    s.backdoor<key>();
    s.backdoor<key>();
}

Producción:

900000
800000
dalle avatar Jan 08 '2009 16:01 dalle

Agregué una entrada a mi blog (ver más abajo) que muestra cómo se puede hacer. Aquí hay un ejemplo de cómo usarlo para la siguiente clase.

struct A {
private:
  int member;
};

Simplemente declare una estructura donde la describa y cree una instancia de la clase de implementación utilizada para el robo.

// tag used to access A::member
struct A_member { 
  typedef int A::*type;
  friend type get(A_member);
};

template struct Rob<A_member, &A::member>;

int main() {
  A a;
  a.*get(A_member()) = 42; // write 42 to it
  std::cout << "proof: " << a.*get(A_member()) << std::endl;
}

La Robplantilla de clase se define así y solo necesita definirse una vez, independientemente de a cuántos miembros privados planee acceder

template<typename Tag, typename Tag::type M>
struct Rob { 
  friend typename Tag::type get(Tag) {
    return M;
  }
};

Sin embargo, esto no muestra que las reglas de acceso de C++ no sean confiables. Las reglas del lenguaje están diseñadas para proteger contra errores accidentales: si intenta robar datos de un objeto, el lenguaje por diseño no tarda mucho en impedirlo.

Johannes Schaub - litb avatar Jul 03 '2010 22:07 Johannes Schaub - litb

Lo siguiente es engañoso, ilegal, depende del compilador y puede no funcionar dependiendo de varios detalles de implementación.

#define private public
#define class struct

Pero es una respuesta a su OP, en el que invita explícitamente a una técnica que, y cito, es "totalmente estúpida y que cualquiera que desee probar algo así en código de producción debería ser despedido y/o fusilado".


Otra técnica consiste en acceder a datos de miembros privados, mediante la construcción de punteros utilizando compensaciones codificadas de forma rígida/codificada a mano desde el principio del objeto.

ChrisW avatar Jan 08 '2009 12:01 ChrisW

Hmmm, no sé si esto funcionaría, pero podría valer la pena intentarlo. Cree otra clase con el mismo diseño que el objeto con miembros privados pero con privado cambiado a público. Cree una variable de puntero a esta clase. Utilice una conversión simple para señalar su objeto con miembros privados e intente llamar a una función privada.

Espere chispas y tal vez un choque;)

SmacL avatar Jan 08 '2009 13:01 SmacL