Доступ к закрытому полю класса извне

420
16 мая 2017, 05:00

Здравствуйте, нашел на неком ресурсе подобный код(немного его модифицировал под себя):

#include <iostream>
using namespace std;
class PrivateClass
{
public:
    PrivateClass(int a, char b)
        : privateInt(a), privateChar(b) {}
    int     getInt() {return privateInt; }
    char    getChar() {return privateChar; }
private:
    int     privateInt;
    char    privateChar;
};
class Stealer
{
public:
    int &stealInt(PrivateClass &clss)
    {
        return ((Stealer *) (&clss))->stealedInt;
    }
    char &stealChar(PrivateClass &clss)
    {
        return ((Stealer *) (&clss))->stealedChar;
    }
private:
    int     stealedInt;
    char    stealedChar;
};
int main()
{
    PrivateClass    prVar(20, 'a');
    Stealer         stVar;
    int &stlInt     = stVar.stealInt(prVar);
    char &stlChar   = stVar.stealChar(prVar);
    cout << "Private Class:\nInt = " << prVar.getInt() << "\nChar = " << prVar.getChar() << endl;
    cout << "\nStealed:\nInt = " << stlInt << "\nChar = " << stlChar << endl;
    stlInt  = -65;
    stlChar = 'q';
    cout << "Int = " << stlInt << "\nChar = " << stlChar << endl;
    cout << "\nPrivate Class:\nInt = " << prVar.getInt() << "\nChar = " << prVar.getChar() << endl;
    return 0;
}

Результат:

Private Class:
Int = 20
Char = a
Stealed:
Int = 20
Char = a
Int = -65
Char = q
Private Class:
Int = -65
Char = q

Как я понял, класс Stealer как-то получил доступ к закрытым полям класса PrivateClass да ещё и по ссылке, что дало возможность менять значения переменной "извне". Увы, я внятного ответа нигде не нашел. Что это может быть?

Answer 1

Тут все совершенно тривиально, что может и быть причиной того, что объяснения отсутствуют.

Класс Stealer просто переинтерпретирует память объекта типа PrivateClass как память объекта типа Stealer. Расположение полей класса Stealer, согласно задумке, должно совпадать с расположением полей класса PrivateClass. Это означает, что, согласно задумке, после такой переинтерпретации, смотря через поля класса Stealer, мы будем "видеть" в памяти соответствующие поля класса PrivateClass.

Подобные трюки нарушают требования strict aliasing языка C++. Код порождает неопределенное поведение и в общем случае неработоспособен.

P.S. Прием, позволяющий легально обойти защиту, предоставляемую private я приводил вот здесь: https://ru.stackoverflow.com/a/656542/182825. В применении к данному случаю: http://coliru.stacked-crooked.com/a/49db7cfe2b1bc36b

Answer 2

Грязный хак :)

Просто сделан аналогичный по структуре класс, и область памяти, занятая одним классом, объявлена как область памяти, занятая другим классом, который позволяет обратиться к его данным, а уж открытые они там или закрытые...

Класс не "получил доступ", он подменил объект другого класса собой. Вернее, даже не объект, а указатель на объект другого класса объявил, как указатель на объект своего класса - с такой же внутренней структурой.

Грубо говоря, подделал паспорт :)

READ ALSO
Преобразовать код Pascal в C++ [требует правки]

Преобразовать код Pascal в C++ [требует правки]

Помогите преобразовать код Pascal в C++

426
Потоки, WaitForMultipleObject

Потоки, WaitForMultipleObject

Здравствуйте, использование WaitForMultipleObject(

344
Можно ли переместить консоль вывода с++ кода во внутреннее поле vscode?

Можно ли переместить консоль вывода с++ кода во внутреннее поле vscode?

По умолчанию при запуске с++ кода открывается внешняя консольЯ же хочу видеть вывод моей программы в качестве одной из вкладок в нижнем поле...

514
Не возвращается нужный return из dll

Не возвращается нужный return из dll

Пытаюсь из dll вернуть значение int в MetaTrader4

391