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


Renuncia

Sí, soy plenamente consciente de que lo que estoy preguntando es totalmente estúpido y que cualquiera que desee probar algo así en el código de producción debe ser despedido y / o fusilado. Principalmente estoy buscando para ver si poder estar hecho.

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

(Bienvenido a las técnicas ingenuas y no preparadas para la producción)

Actualizar

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

En cualquier caso, si alguien está interesado en cómo salió, aquí está: Enemigos del desarrollo impulsado por prueba parte I: encapsulación (Sugiero leerlo antes de decidir que estoy loco).


58
2018-01-08 12:45


origen


Respuestas:


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

seguro.h

class safe
{
    int money;

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

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

main.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>();
}

Salida:

900000
800000

65
2018-01-08 16:43



He agregado un entrada a mi blog (ver abajo) que muestra cómo se puede hacer. Aquí hay un ejemplo de cómo lo usa para la siguiente clase

struct A {
private:
  int member;
};

Simplemente declare una estructura donde la describa y ejemplifique 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;
}

los Rob La plantilla de clase se define así, y solo necesita definirse una vez, sin importar a cuántos miembros privados tiene previsto 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 de idioma están diseñadas para proteger contra errores accidentales: si intenta robar datos de un objeto, el idioma por diseño no toma mucho tiempo para prevenirlo.


47
2017-07-03 22:38



Lo siguiente es furtivo, ilegal, dependiente 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 la que invita explícitamente a una técnica que, y cito, es "totalmente estúpida y que cualquiera que desee probar tal cosa en el código de producción debe ser despedido y / o fusilado".


Otra técnica es acceder a datos de miembros privados, mediante la construcción de punteros utilizando desplazamientos codificados a mano / codificados a mano desde el comienzo del objeto.


29
2018-01-08 12:53



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. Crea una variable de puntero a esta clase. Utiliza un simple molde para señalar esto a tu objeto con miembros privados e intenta llamar a una función privada.

Esperar chispas y tal vez un choque;)


23
2018-01-08 13:04



class A 
{ 
   int a; 
}
class B
{
   public: 
   int b;
}

union 
{ 
    A a; 
    B b; 
};

Deberias hacer eso.

ETA: Funcionará para este tipo de clase trivial, pero como algo general, no lo hará.

TC ++ PL Sección C.8.3: "Una clase con una operación de constructor, destructor o de copia no puede ser del tipo de un miembro de la unión ... porque el compilador no sabría qué miembro destruir".

Así que nos quedamos con la mejor apuesta para declarar class B para hacer coincidir Adiseño y pirateo para ver las partes privadas de una clase.


12
2018-01-09 03:41



Definitivamente es posible acceder a miembros privados con un desplazamiento de puntero en C ++. Supongamos que tengo la siguiente definición de tipo a la que quería acceder.

class Bar {
  SomeOtherType _m1;
  int _m2;
};

Suponiendo que no hay métodos virtuales en Bar, el caso fácil es _m1. Los miembros en C ++ se almacenan como desplazamientos de la ubicación de la memoria del objeto. El primer objeto está en offset 0, el segundo objeto en offset de sizeof (primer miembro), etc ...

Así que aquí hay una forma de acceder a _m1.

SomeOtherType& GetM1(Bar* pBar) {
  return*(reinterpret_cast<SomeOtherType*>(pBar)); 
}

Ahora _m2 es un poco más difícil. Necesitamos mover el tamaño del puntero original de (SomeOtherType) bytes desde el original. El cast a char es para asegurarme de que estoy incrementando en una compensación de bytes

int& GetM2(Bar* pBar) {
  char* p = reinterpret_cast<char*>(pBar);
  p += sizeof(SomeOtherType);
  return *(reinterpret_cast<int*>(p));
}

8
2018-01-08 15:34



Si puede obtener un puntero a un miembro de una clase, puede usar el puntero sin importar cuáles sean los especificadores de acceso (incluso los métodos).

class X;
typedef void (X::*METHOD)(int);

class X
{
    private:
       void test(int) {}
    public:
       METHOD getMethod() { return &X::test;}
};

int main()
{
     X      x;
     METHOD m = x.getMethod();

     X     y;
     (y.*m)(5);
}

Por supuesto, mi truco favorito es la puerta trasera de la plantilla de amigos.

class Z
{
    public:
        template<typename X>
        void backDoor(X const& p);
    private:
        int x;
        int y;
};

Suponiendo que el creador de lo anterior haya definido BackDoor para sus usos normales. Pero desea acceder al objeto y observar las variables de miembros privados. Incluso si la clase anterior se compiló en una biblioteca estática, puede agregar su propia especialización de plantilla para backDoor y así acceder a los miembros.

namespace
{
    // Make this inside an anonymous namespace so
    // that it does not clash with any real types.
    class Y{};
}
// Now do a template specialization for the method.
template<>
void Z::backDoor<Y>(Y const& p)
{
     // I now have access to the private members of Z
}

int main()
{
    Z  z;   // Your object Z

    // Use the Y object to carry the payload into the method.
    z.backDoor(Y());
}

8
2018-01-08 19:13



pregunta genial por cierto ... aquí está mi pieza:

using namespace std;

class Test
{

private:

  int accessInt;
  string accessString;

public:

  Test(int accessInt,string accessString)
  {
    Test::accessInt=accessInt;
    Test::accessString=accessString;
  }
};

int main(int argnum,char **args)
{
  int x;
  string xyz;
  Test obj(1,"Shit... This works!");

  x=((int *)(&obj))[0];
  xyz=((string *)(&obj))[1];

  cout<<x<<endl<<xyz<<endl;
  return 0;
}

Espero que esto ayude.


4
2018-03-29 09:03