Почему этот код шаблона может нарушать спецификатор частного доступа C ++? - PullRequest
7 голосов
/ 24 ноября 2011

В следующем коде, который я нашел здесь:

http://bloglitb.blogspot.com/2010/07/access-to-private-members-thats-easy.html

кажется, что он переходит прямо через спецификатор частного доступа C ++.Это позволяет мне вызывать частные функции и читать / записывать личные данные членов.

Поиск SO обнаружил эту связанную проблему, которая была подтвержденной ошибкой компилятора GCC

шаблон c ++, кажется, нарушает спецификаторы доступа

Естественно, я попытался использовать тестовый код этого парня.Что было интересно, так это то, что мой компилятор gcc 4.5 действительно имеет эту ошибку (он принимает код и печатает личную информацию), несмотря на то, что об этом сообщалось в gcc 4.3, а я использовал 4.5.

В любом случае, я пошел в Comeauонлайн-компилятор, который некоторые из ответов в ветке сказали, что пытались.Я подтвердил, что Comeau не принимает код из этого вопроса, но принимает мой код ниже.

Итак, в конечном итоге мой вопрос заключается в том, наткнулся ли я на ошибку в GCC и компиляторе Comeau C ++?Это компилируется с VC ++?Если это не ошибка, может кто-нибудь объяснить, как это работает?Я понял, что он может объявить статический указатель на функцию-член и указать его на закрытый раздел, но как это сделать?

Разное: Да, я знаю, что на самом деле это очень, очень плохо.Это также будет работать, если вы объявите ptr данных члена и позволите вам читать / записывать личные данные.Некоторые из странных комментариев были от меня, пытающегося маркировать это для понимания.Я не вызывал в воображении этот код и не возьму на себя ответственность за это.Я только что нашел это в Google.У меня может не хватить очков репутации, чтобы отвечать на комментарии, но я прочитаю все, что вы скажете.Спасибо, что заглянули.

#include <iostream>

using namespace std;


//--------------------------------------------
//
template<typename Tag>
struct result 
{
  /* export it ... */
  typedef typename Tag::type type;

  static type ptr;
};


// allocate space for the static member
template<typename Tag>
typename result<Tag>::type result<Tag>::ptr;

//--------------------------------------------

template<typename Tag, typename Tag::type p>
struct rob : result<Tag> 
{
  /* fill it ... */
  struct filler 
  {
      filler() { result<Tag>::ptr = p; }
  };

  static filler filler_obj;
};

// allocate space for the static member
template<typename Tag, typename Tag::type p>
typename rob<Tag, p>::filler rob<Tag, p>::filler_obj;
//--------------------------------------------


struct A 
{
  private:

    void f() 
    {   
        cout << "hey, don't touch me I'm private!" << endl;
    }
};

struct Af  
{ 
    typedef void(A::*type)(); 
};
template class rob<Af, &A::f>;



int main()
{
    A a;
    (a.*result<Af>::ptr)();
}

~> ./a.out эй, не трогай меня, я личный!

~> g ++ - версия g ++ (SUSE Linux) 4.5.0 20100604 [версия gcc-4_5-ветви 160292] Copyright (C) 2010 Free Software Foundation, Inc.

1 Ответ

3 голосов
/ 24 ноября 2011

Как сказал Локи Астари, public и private - это всего лишь семантика для компилятора, поэтому он может дать вам предупреждение о том, что вы не используете свой код так, как вы планировали.

Я не слишком много играю с указателями на методы (если вообще), поэтому у меня не хватает терпения, чтобы полностью это выяснить. Но это ничем не отличается от выполнения следующих То есть, используя логику указателя, чтобы указать на любой бит памяти, который вы хотите, и вызывать функции и методы и неправильно их использовать.

#include <iostream>

using namespace std;

struct A 
{
  public:
    void g()
    {
      cout << "value of i is " << this->i << endl;
    }
    void setJ(int newJ) {
      j = newJ;
    }
    int i;
  private:
    int j;
};

int main() {

    A a;
    a.i = 5;
    a.setJ(10);

    // accessing private field j
    cout << "value of j is " << *((&a.i)+1) << endl;

    // creating a pointer to method g    
    void(A::*method)() = &A::g;

    // changing it to be a function pointer
    void(*function)(A*) = (void(*)(A*)) method;

    // using function pointer to call A::g  
    function(&a);  

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...