Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Хитрый доступ к private полям/методам класса


Автор: Aqs 12.5.2010, 19:09
Здравствуйте!
Вопрос таков - как получить из внешней функции доступ к private полям и методам класса, при этом ничего в самом классе не изменяя ? (вариант объявить методы и поля как public тоже не подходит) 

Например, из main, модифицировать и вывести на экран поле a, и вызвать метод c, определенные в следующем тривиальном классе:
Код

class A {
      int a;
      int b () {
          return 345;
      }
}; 


Подозреваю, что нужно как-то добираться до них через адреса, но сколько не пробовал - никак не выходит.  
Прошу совета.

Автор: azesmcar 12.5.2010, 20:28
через грязные хаки
Код

#define private public
#define class struct

class A {
      int a;
      int b () {
          return 345;
      }
};

но это непереносимо, стандарт не позволяет определять макросы с ключевыми словами.
Цитата

A translation unit that includes a header shall not contain any macros that define names declared or defined
in that header. Nor shall such a translation unit define macros for names lexically identical to keywords.


Добавлено через 1 минуту и 9 секунд
еще для доступа к переменным можно подменить класс идентичным через reinterpret_cast..

но зачем это надо?

Автор: toxx 12.5.2010, 20:38
azesmcar
сорри за оффтоп , но напоминает идусский код...  smile 
Код

#define true false

Автор: azesmcar 12.5.2010, 20:39
Цитата(toxx @  12.5.2010,  20:38 Найти цитируемый пост)
сорри за оффтоп , но напоминает идусский код...  smile 

так и есть smile только на логику выполнения не влияет.
вот это кстати получше
Код

#define sizeof(X) rand()

Автор: Aqs 12.5.2010, 20:45
Цитата(azesmcar @ 12.5.2010,  20:28)
но зачем это надо?

Задание такое получил, в университете... smile

Автор: kemiisto 12.5.2010, 20:49
Цитата(Aqs @  12.5.2010,  21:45 Найти цитируемый пост)
Задание такое получил, в университете...

Да, всё правильно написали. smile Такие университеты только с маленькой буквый и писать. А по-хорошему...

Автор: azesmcar 12.5.2010, 20:49
Не устану повторять, такие вопросы лучше задавать в google-е...он все знает
user posted image

Автор: Aqs 12.5.2010, 20:57
Если бы было так легко найти, я бы уже давно нашел smile Перерыл за сегодня не один десяток форумов и сайтов - именно такая задача не встречается нигде.
Понадеялся что тут найдутся знающие люди, которые помогут.
Кстати, вариант с грязными хаками неподходит - нужно что-то более "легальное" smile Да и препод намекнул, что тут до полей и методов нужно добираться именно через адрес.

Автор: azesmcar 12.5.2010, 21:06
Цитата(Aqs @  12.5.2010,  20:57 Найти цитируемый пост)
Если бы было так легко найти, я бы уже давно нашел smile Перерыл за сегодня не один десяток форумов и сайтов - именно такая задача не встречается нигде.

Я показал что надо искать smile 
хотя если серьезно то тем в интернете дофига
http://www.google.mu/search?hl=en&client=firefox-a&hs=IZb&rls=org.mozilla%3Aen-US%3Aofficial&q=access++private+variables+C%2B%2B&aq=f&aqi=&aql=&oq=&gs_rfai=

Цитата(Aqs @  12.5.2010,  20:57 Найти цитируемый пост)
Кстати, вариант с грязными хаками неподходит - нужно что-то более "легальное" smile Да и препод намекнул, что тут до полей и методов нужно добираться именно через адрес. 

легальный способ friend-ы, еще можно через шаблоны, игры с адресами - грязный хак.
Код

A t;
std::cout << *((int*)&t) << std::endl;

до переменный можно добраться так, до функции насколько я помню никак не добраться без макросов.

Автор: Леопольд 12.5.2010, 22:00
Цитата(Aqs @  12.5.2010,  20:45 Найти цитируемый пост)
Задание такое получил
Препод, видимо, С++ по Подбельски учил... smile В общем, учит он абсолютно ненужной фигне. Бредятина. Лучше бы задал реализовать какой-нибудь паттерн проектирования. Хотя, он наверное и слова такого не слышвл...

Автор: Alek86 12.5.2010, 22:05
есть только один нормальный способ это сделать, но только если у класса есть хоть одна неприватная шаблонная функция-член
описан у Саттера, причем очень красиво

но уверен, препод его в виду не имел

Автор: Леопольд 12.5.2010, 22:08
Цитата(Alek86 @  12.5.2010,  22:05 Найти цитируемый пост)
но уверен, препод его в виду не имел
Цитата(Aqs @  12.5.2010,  19:09 Найти цитируемый пост)
при этом ничего в самом классе не изменяя


Добавлено через 3 минуты и 29 секунд
Цитата(azesmcar @  12.5.2010,  21:06 Найти цитируемый пост)
до переменный можно добраться так
А если с множественным наследованием или виртуальными функциями? Вроде бы, если это не POD, то behaviour is undefined.

Автор: azesmcar 12.5.2010, 22:21
Цитата(Леопольд @  12.5.2010,  22:08 Найти цитируемый пост)
А если с множественным наследованием или виртуальными функциями? Вроде бы, если это не POD, то behaviour is undefined. 

Я уже написал что это грязный и непереносимый хак, который к тому же касался конкретно описанного класса.

Автор: Леопольд 12.5.2010, 22:31
azesmcar, я понимаю что ты знал почему это хак.  smile Я топикстартера на мысль навёл.

Автор: Леопольд 12.5.2010, 22:48
Вот мой вариант "бреда"  smile Но, пришлось немного поменять исходный класс.

http://codepad.org/uRXBy0SZ 
Код
#include <iostream>

class A {
      int a;
      virtual int b () {
          return a;
      }
};
struct B{
      int a;
      virtual int b ();
};

int main(){
    A obj;
    B* ptr = static_cast<B*>(static_cast<void*>((&obj)));
    ptr->a = 123;
    std::cout<<ptr->b()<<std::endl;
    return 0;
}


Твоему чокнутому профессору должно понравиться, ведь ещё и на vtbl завязано.  smile 
Разберись что такое "виртуальная таблица функций" и по ушам ему этим проедь. Глядишь, зачтёт. Ты главное напирай на то, что это зачётно! smile

З.Ы. Это пример как нельзя кодить.

Автор: Alek86 12.5.2010, 22:57
Цитата(Леопольд @  12.5.2010,  22:08 Найти цитируемый пост)
Цитата(Alek86 @  12.5.2010,  22:05 )но уверен, препод его в виду не имелЦитата(Aqs @  12.5.2010,  19:09 )при этом ничего в самом классе не изменяя

ну и чего в классе в случае шаблона меняется? специализации могут быть хоть в другом cpp

Автор: Леопольд 12.5.2010, 23:01
Цитата(Alek86 @  12.5.2010,  22:57 Найти цитируемый пост)

ну и чего в классе в случае шаблона меняется?
Цитата(Alek86 @  12.5.2010,  22:05 Найти цитируемый пост)
но только если у класса есть хоть одна неприватная шаблонная функция-член
Ты меня, видимо, неправильно понял. Нет такой функции в исходном классе (см. первый пост).

Автор: Alek86 12.5.2010, 23:02
Цитата(Леопольд @  12.5.2010,  22:48 Найти цитируемый пост)
Вот мой вариант "бреда"   Но, пришлось немного поменять исходный класс.

а зачем виртуальные функции?

Автор: Леопольд 12.5.2010, 23:08
Цитата(Alek86 @  12.5.2010,  23:02 Найти цитируемый пост)

а зачем виртуальные функции? 
Обрати внимание на то, что функция b реализована только в A классе. ptr->b() вызывается через vtbl класса A. Я же говорю, зачётно. smile

Автор: Aqs 12.5.2010, 23:13
Спасибо за идею, но... Исходный класс изменять нельзя вообще никак, в этом-то и вся соль - у меня тоже была мысль что-то замутить с виртуальными функциями, но без переобъявления метода b как виртуального и в классе А, ничего не выйдет. А делать этого нельзя, по условию. Да и с виртуальными функциями уже по курсу имели тесное общение - мозги ему запудрить неполучится  smile 

С полями вроде разобрался... Идея похожа на Вашу (используется так же вспомогательный класс) :
Код

#include <iostream>

class A{
    int a;
    int b() { return 123; }
public:
    A() : a(10) {}
};

struct Clone { int a; };

int main( ){
    A a;
    void *pv = &a; 
    Clone *pc = (Clone*)pv; 
    std::cout<<pc->a<<std::endl; 
}


А вот с методами по-прежнему непонятно что делать.

Автор: Леопольд 12.5.2010, 23:19
Цитата(Aqs @  12.5.2010,  23:13 Найти цитируемый пост)
А вот с методами по-прежнему непонятно что делать. 
Цитата(azesmcar @  12.5.2010,  21:06 Найти цитируемый пост)

до переменный можно добраться так, до функции насколько я помню никак не добраться без макросов. 

Aqs, я ему верю больше чем твоему преподу - маньяку.  smile 

Автор: Aqs 12.5.2010, 23:24
Цитата(Леопольд @  12.5.2010,  23:19 Найти цитируемый пост)
Aqs, я ему верю больше чем твоему преподу - маньяку.  smile  

Да, я тоже с каждым часом начинаю всё больше сомневаться в реализуемости этого... smile
Хотя конечно может решение и есть, но видимо только преподы-маньяки знают его smile 

Автор: Леопольд 12.5.2010, 23:25
http://codepad.org/6Ll4wy13
Нельзя взять адрес приватной функции.

Автор: mes 13.5.2010, 12:15
Цитата(Aqs @  12.5.2010,  22:24 Найти цитируемый пост)
Да, я тоже с каждым часом начинаю всё больше сомневаться в реализуемости этого... 

попробую развеять сомнения smile

Код

// a.h 
...
class A {
    int a;
    int b ();
};

Код

//a.cpp
#include "a.h"
int A::b () { return 345; }

Код

//main.cpp

class A; // forward declaration

void hack_init  (A&);   
void hack_print (A&); // прототипы хак-функций (можно вынести в а_hack.h)

#include <a.h> // включаем оригинал после прототипов

int main() 
{
    A a;
    hack_init  (a);
    hack_print (a);    //  применяем хак-функции
     
    
    return 0;
}

Код

// a_hack.cpp
#include <iostream>

// хак-копия класса 
// должна иметь то же самое имя,  но может быть объявлена как структура,
// порядок дата-членов должен быть соблюден
// приват-функция оригинала не должна быть инлайн.. (определена внутри класса), иначе ее тоже нужно определять в hack-копии
struct A {

    int a;
    int b ();
};  

void hack_init (A& obj)
{
    obj.a = 7;
}


void hack_print (A& obj)
{
    std::cout << obj.a << " " << obj.b();
}


надеюсь очепяток не допустил smile

Автор: Aqs 13.5.2010, 14:05
mes, спасибо! Действительно, всё отлично работает smile
Только вот осталось непонятным, почему обязательно нужно объявлять b() вне класса A ?
Если b() будет объявлена внутри, то получается нужно в структуре продублировать код функции? 


Автор: mes 13.5.2010, 15:03
Цитата(Aqs @  13.5.2010,  13:05 Найти цитируемый пост)
Если b() будет объявлена внутри, то получается нужно в структуре продублировать код функции? 

ага 

Цитата(mes @  13.5.2010,  11:15 Найти цитируемый пост)
приват-функция оригинала не должна быть инлайн.. (определена внутри класса), иначе ее тоже нужно определять в hack-копии


или можно поступить проще, воспользоваться дефайнами, как предлaгал azesmzar, 
но применить его только в a_hack.cpp файле, так сказать компромисс - весь хак будет собран в одном месте и никого другого не зацепит.. smile

Код

// a_hack.cpp
#include <iostream>

#define class struct
#define private public
#define protected public

#include "a.h"
  
void hack_init (A& obj)
...

Автор: Alek86 13.5.2010, 16:16
mes, это нестандартно
сильно подозреваю, что твое решение нестандартно тоже, хотя четких доказательств нету

Автор: mes 13.5.2010, 18:05
Цитата(Alek86 @  13.5.2010,  15:16 Найти цитируемый пост)
хотя четких доказательств нету 

ну тут  доказывать то сильно и не надо - достаточно того, что у нас получаются два разных описания класса smile
насчет нестандартности метода, я думаю, также говорили префиксы имен функций hack_ smile
но .. раз преподу хочется,   сделаем ему приятное smile

Автор: Alek86 13.5.2010, 21:50
Цитата(mes @  13.5.2010,  18:05 Найти цитируемый пост)
достаточно того, что у нас получаются два разных описания класса

вот я и не знаю, запрещает ли это стандарт явно
шаблонные методы тоже могут привести к разным описаниям...

Автор: mes 13.5.2010, 23:35
Цитата(Alek86 @  13.5.2010,  20:50 Найти цитируемый пост)
вот я и не знаю, запрещает ли это стандарт явно
шаблонные методы тоже могут привести к разным описаниям... 

нда.. сформулировал я неправильно.. разные описания это не проблема, зависит от того что разное smile
имелось ввиду то, что описание приводит к различным "представлениям".

В стандарте (раздел ODR) накладывается ряд ограничений, после которых обе копии считаются идентичными, но рассматривается ли там наша ситуация, я так и не понял smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)