[Trick] Легальный способ доступа к закрытым членам
От: rg45 СССР  
Дата: 25.09.18 14:32
Оценка: 81 (13)
Наверное, у каждого бывали в жизни случаи, когда очень хотелось получить несанкционированный доступ к закрытым членам какого-то класса. Ну вот понимаешь, что нельзя, но очень хочется. А знаете ли вы, что это можно сделать абсолютно легально и в соответствии со стандартом С++? Ну, кто-то знает, а кто-то нет. Фокус в том, что существует один сценарий, когда мы имеем полное право использовать имя закрытого члена класса. Это случай явного инстанцированя какого-нибудь шаблона:

17.7.2 Explicit instantiation
12 The usual access checking rules do not apply to names used to specify explicit instantiations.


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

Эскизный пример реализации и использования здесь:

https://ideone.com/ttt4pI [Upd]: пофикшена ошибка, ссылка обновлена

Использование выглядит примерно так:

class A
{
public:
 
   explicit A(int value) : m_value(value) { }
 
   int GetValue() const { return m_value; }
 
private:
   int m_value;
};
 
ENABLE_PIVATE_MEMBER_ACCESS(A_value, A, int, m_value)
 
int main()
{
   A a(1);
   std::cout << "a.GetValue(): " << a.GetValue() << std::endl;
   *PrivateMemberAccessor<A_value>(a) = 42;
   std::cout << "a.GetValue(): " << a.GetValue() << std::endl;
}
--
Отредактировано 25.09.2018 18:10 rg45 . Предыдущая версия . Еще …
Отредактировано 25.09.2018 14:49 rg45 . Предыдущая версия .
Re: [Trick] Легальный способ доступа к закрытым членам
От: Nikе Россия  
Дата: 25.09.18 14:54
Оценка: 9 (1) :)
Здравствуйте, rg45, Вы писали:

А зачем так заморачиваться, если 100 лет есть паттерн: Public Morozov?
Нужно разобрать угил.
Re[2]: [Trick] Легальный способ доступа к закрытым членам
От: Nikе Россия  
Дата: 25.09.18 14:55
Оценка:
Здравствуйте, Nikе, Вы писали:

N>А зачем так заморачиваться, если 100 лет есть паттерн: Public Morozov?


Хотя... Это одна из его возможных реализаций, так что ок.
Нужно разобрать угил.
Re[2]: [Trick] Легальный способ доступа к закрытым членам
От: rg45 СССР  
Дата: 25.09.18 14:57
Оценка:
Здравствуйте, Nikе, Вы писали:

N>А зачем так заморачиваться, если 100 лет есть паттерн: Public Morozov?


Ну чисто из академических соображений. Просто чтоб знать, что есть вот еще такой способ.
--
Re: [Trick] Легальный способ доступа к закрытым членам
От: kov_serg Россия  
Дата: 25.09.18 15:47
Оценка: +1 -2 :))) :)))
Здравствуйте, rg45, Вы писали:

R>Эскизный пример реализации и использования здесь:

R>https://ideone.com/meuOaW
Это должно быть здесь
Re[2]: [Trick] Легальный способ доступа к закрытым членам
От: Nikе Россия  
Дата: 25.09.18 15:56
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Это должно быть здесь

_>Image: 2013_09_10_12_12_allunix_ru_back_screamingrobot.jpg
А почему бы и нет?
Нужно разобрать угил.
Re[3]: [Trick] Легальный способ доступа к закрытым членам
От: Vain Россия google.ru
Дата: 25.09.18 21:44
Оценка:
Здравствуйте, Nikе, Вы писали:

_>>Image: 2013_09_10_12_12_allunix_ru_back_screamingrobot.jpg

N>А почему бы и нет?
Новый тренд: русские программисты (на манер британских учоных)
Когда им нечем заняться, они придумывают публичный доступ к закрытым данным.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Отредактировано 25.09.2018 21:48 Vain . Предыдущая версия .
Re[2]: [Trick] Легальный способ доступа к закрытым членам
От: andrey.desman  
Дата: 25.09.18 23:51
Оценка: +2
Здравствуйте, Nikе, Вы писали:

N>А зачем так заморачиваться, если 100 лет есть паттерн: Public Morozov?



Паблик М. может сборку навернуть, т.к. уровень доступа может участвовать в имени методов (mangling).
Re[4]: [Trick] Легальный способ доступа к закрытым членам
От: B0FEE664  
Дата: 26.09.18 07:39
Оценка: +1 :))) :)))
Здравствуйте, Vain, Вы писали:

N>>А почему бы и нет?

V>Новый тренд: русские программисты (на манер британских учоных)
V>Когда им нечем заняться, они придумывают публичный доступ к закрытым данным.

Russian hackers, sir.
И каждый день — без права на ошибку...
Re: [Trick] Легальный способ доступа к закрытым членам
От: _NN_ www.nemerleweb.com
Дата: 27.09.18 07:27
Оценка:
Здравствуйте, rg45, Вы писали:

Хотелось бы тут выводить типы A и int автоматически.

R>ENABLE_PIVATE_MEMBER_ACCESS(A_value, A, int, m_value)


Использование decltype в специализации компилируется, но любые попытки использовать дальше не увенчались успехом.
Есть идеи ?

template<typename MemberPtrT, MemberPtrT>
struct X;

template<> struct X<decltype(&A::m_value), &A::m_value> // : Base<decltype(&A::m_value)> // нет доступа
{
    // using Q = decltype(&A::m_value);  // нет доступа
};
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: [Trick] Легальный способ доступа к закрытым членам
От: rg45 СССР  
Дата: 27.09.18 08:09
Оценка: +1
Здравствуйте, _NN_, Вы писали:


_NN>Использование decltype в специализации компилируется, но любые попытки использовать дальше не увенчались успехом.

_NN>Есть идеи ?

Убил на это уйму времени, результат — ноль

Я пробовал обеспечить доступ через дружественные фунции. На msvc работает, на gcc — нет. Причем, gcc прав

P.S. Кстати, если бы это удалось сделать, то одновремено с этим получилось бы сделать указатель на член constexpr, а не защелкивать его в runtime переменной, как сейчас.
--
Отредактировано 27.09.2018 8:19 rg45 . Предыдущая версия . Еще …
Отредактировано 27.09.2018 8:11 rg45 . Предыдущая версия .
Отредактировано 27.09.2018 8:11 rg45 . Предыдущая версия .
Re[3]: [Trick] Легальный способ доступа к закрытым членам
От: _NN_ www.nemerleweb.com
Дата: 27.09.18 08:45
Оценка:
Здравствуйте, rg45, Вы писали:

R>Я пробовал обеспечить доступ через дружественные фунции. На msvc работает, на gcc — нет. Причем, gcc прав


Где код ?
Может получиться что-нибудь придумать.

R>P.S. Кстати, если бы это удалось сделать, то одновремено с этим получилось бы сделать указатель на член constexpr, а не защелкивать его в runtime переменной, как сейчас.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: [Trick] Легальный способ доступа к закрытым членам
От: rg45 СССР  
Дата: 27.09.18 08:57
Оценка:
Здравствуйте, _NN_, Вы писали:

R>>Я пробовал обеспечить доступ через дружественные фунции. На msvc работает, на gcc — нет. Причем, gcc прав


_NN>Где код ?

_NN>Может получиться что-нибудь придумать.

Не сохранился, восстановлю, как появится свободная минутка. Идея основывается на том, что в некоторых случаях ADL заглядывает внутрь классов в поисках дружественных функций. Только по стандарту, это делается только в том случае, если в сигнатуре функции присутствует какая-то связь с классом, дружественной которому эта функция является. gcc постуает строго, как написано в стандарде. А msvc более "либеральна" в этом плане. Таким образом нужный указатель на член можно запаковать в тип возвращаемого значения, а потом вытащить его при помощи внешней метафункции.
--
Re: [Trick] Легальный способ доступа к закрытым членам
От: kov_serg Россия  
Дата: 27.09.18 12:59
Оценка:
Здравствуйте, rg45, Вы писали:

R>Наверное, у каждого бывали в жизни случаи, когда очень хотелось получить несанкционированный доступ к закрытым членам какого-то класса.


Поэтому я по возможности предпочитаю такие приватные поля.
// Public.h
struct Public {
    static Public* create(int value);
    virtual int getValue() const=0;
    virtual ~Public() {}
};

// Public_create.cpp
#include "public.h"
#include "a_lot_of_trash_and_other_dependencies"

struct Private : Public {
    int value;
    Private(int value) : value(value) {}
    int getValue() const { return value; }
};

Public* Public::create(int value) {
    return new Private(value);
}

Уменьшается время компиляции и связность, улучшается читаемость и не хочеться несанкционированного доступа
А то что в C++ называется private ниразу не private оно не скрывает реализации просто осложняет доступ.
Зато тянет за собой зависимости связанные с типом приватного поля и его реализацией, чего в большинстве случаев нафиг не упало.
Re[2]: [Trick] Легальный способ доступа к закрытым членам
От: rg45 СССР  
Дата: 27.09.18 13:22
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Поэтому я по возможности предпочитаю такие приватные поля.

_>Уменьшается время компиляции и связность, улучшается читаемость и не хочеться несанкционированного доступа
_>А то что в C++ называется private ниразу не private оно не скрывает реализации просто осложняет доступ.
_>Зато тянет за собой зависимости связанные с типом приватного поля и его реализацией, чего в большинстве случаев нафиг не упало.

Я, в общем-то, имею кое-какое представление и о способах сокрытия реализации, и об абстракных классах, их преимуществах и областях применимости. Я только не очень понимаю, зачем ты здесь обо всем этом рассказываешь. Вопрос, по-моему, был поставлен предельно ясно: "кто хочет вишенку, вот вам вишенка". Кто не хочет, тот не ест. Ты же, зачем-то, пытаешься убедить всех, что хотеть вишенку — это плохо, потому, что на Луне вишни не растут
--
Отредактировано 27.09.2018 13:28 rg45 . Предыдущая версия . Еще …
Отредактировано 27.09.2018 13:22 rg45 . Предыдущая версия .
Re[3]: [Trick] Легальный способ доступа к закрытым членам
От: kov_serg Россия  
Дата: 27.09.18 14:05
Оценка:
Здравствуйте, rg45, Вы писали:

R>Я, в общем-то, имею кое-какое представление и о способах сокрытия реализации, и об абстракных классах, их преимуществах и областях применимости. Я только не очень понимаю, зачем ты здесь обо всем этом рассказываешь. Вопрос, по-моему, был поставлен предельно ясно: "кто хочет вишенку, вот вам вишенка". Кто не хочет, тот не ест. Ты же, зачем-то, пытаешься убедить всех, что хотеть вишенку — это плохо, потому, что на Луне вишни не растут

Просто так, не обижайся. Я знаю что у вас черный пояс по C++, но нафига такие вишни? Как вообще пришла в голову идея лезть туда где написано не лезь убъёт?
И что мешало просто вместо private просто написать public или define-ом (#define RELEASE_PRIVATE public) это сделать.
Более того что сечас легальный способ в новом стандарте может перейти в разряд UB, что бы не было скучно.
Re[2]: [Trick] Легальный способ доступа к закрытым членам
От: ViTech  
Дата: 27.09.18 19:34
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Использование decltype в специализации компилируется, но любые попытки использовать дальше не увенчались успехом.

_NN>Есть идеи ?

_NN>
_NN>template<typename MemberPtrT, MemberPtrT>
_NN>struct X;

_NN>template<> struct X<decltype(&A::m_value), &A::m_value> // : Base<decltype(&A::m_value)> // нет доступа
_NN>{
_NN>    // using Q = decltype(&A::m_value);  // нет доступа
_NN>};
_NN>


Может как-то так:
template <class MemberPtr_>
struct Y
{
    using MemberPtr = MemberPtr_;
};

template <class MemberPtr>
struct X;

template <>
struct X<Y<decltype(&A::m_value)>>
{};


template <class MemberPtr>
struct X;

template <class T>
struct K {};

template <class MemberPtr_>
struct K<X<MemberPtr_>>
{
    using MemberPtr = MemberPtr_;
};

template <>
struct X<decltype(&A::m_value)>
{
    using MemberPtr = typename K<X>::MemberPtr;
};
Пока сам не сделаешь...
Re[3]: [Trick] Легальный способ доступа к закрытым членам
От: _NN_ www.nemerleweb.com
Дата: 28.09.18 11:35
Оценка: +1
Здравствуйте, ViTech, Вы писали:

В том и дело, что в специализации можно использовать decltype, но за пределами уже нельзя.
Например тут как добраться до MemberPtr ?
template <>
struct X<decltype(&A::m_value)>
{
    using MemberPtr = typename K<X>::MemberPtr;
};


X<decltype(&A::m_value)::MemberPtr не скомпилируется.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: [Trick] Легальный способ доступа к закрытым членам
От: _NN_ www.nemerleweb.com
Дата: 28.09.18 12:28
Оценка:
Здравствуйте, _NN_, Вы писали:

Объявить дружественную функцию не проблема.
Может есть идеи как протащить дальше?


template <class XX>
typename XX::MemberPtr F(){}


template <class MemberPtr>
struct X;

template <class T>
struct K {};

template <class MemberPtr_>
struct K<X<MemberPtr_>>
{
    using MemberPtr = MemberPtr_;
};

template <>
struct X<decltype(&A::m_value)>
{
    using MemberPtr = typename K<X>::MemberPtr;

    friend X F(); // auto F() -> int (A::*)
};
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: Восстановил (msvc only)
От: rg45 СССР  
Дата: 28.09.18 13:02
Оценка: 9 (1)
Здравствуйте, _NN_, Вы писали:


_NN>Где код ?

_NN>Может получиться что-нибудь придумать.

Вот, восстановил, все-таки. Это работает на mcvc, но не работает на gcc. Ключевой момент в том, что по стандарту хелперная функция не должна в этом случае вноситься в область видимости пространства имен. Но вот на msvc вносится. Э-х-х! сколько клевых фишек можно было бы сделать, будь это стандартым поведением! Синтаксическим сахаром на этор раз не стал особо заморачиваться, ибо все равно не портабельно:

#include <iostream>
#include <utility>

template<typename TagT, typename MemPtrT, MemPtrT memPtr>
struct PrivateMemerAccessEnabler
{
   using PointerToMemberType = MemPtrT;
   static constexpr const PointerToMemberType pointerToMember = memPtr;
   friend PrivateMemerAccessEnabler privateMemerAccessEnablerAux(TagT&&);
};

template <typename TagT>
using PrivateMemberAccess = decltype(privateMemerAccessEnablerAux(std::declval<TagT>()));

#define ENABLE_PRIVATE_MEMBER_ACCESS(TagT, memPtr) \
   template struct PrivateMemerAccessEnabler<struct TagT, decltype(memPtr), memPtr>;

struct A
{
public:

   int GetValue() const { return value; }

private:
   int value = -1;
};

ENABLE_PRIVATE_MEMBER_ACCESS(A_value, &A::value)

int main()
{
   const auto& memPtr = PrivateMemberAccess<A_value>::pointerToMember;

   A a;
   std::cout << a.GetValue() << std::endl;
   a.*memPtr = 42;
   std::cout << a.GetValue() << std::endl;
}
--
Отредактировано 28.09.2018 13:23 rg45 . Предыдущая версия . Еще …
Отредактировано 28.09.2018 13:21 rg45 . Предыдущая версия .
Отредактировано 28.09.2018 13:15 rg45 . Предыдущая версия .
Отредактировано 28.09.2018 13:10 rg45 . Предыдущая версия .
Отредактировано 28.09.2018 13:05 rg45 . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.