Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@dabrahams
Created December 28, 2011 17:50
Show Gist options
  • Star 45 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save dabrahams/1528856 to your computer and use it in GitHub Desktop.
Save dabrahams/1528856 to your computer and use it in GitHub Desktop.
Accessing Private Data
#include <iostream>
// This is a rewrite and analysis of the technique in this article:
// http://bloglitb.blogspot.com/2010/07/access-to-private-members-thats-easy.html
// ------- Framework -------
// The little library required to work this magic
// Generate a static data member of type Tag::type in which to store
// the address of a private member. It is crucial that Tag does not
// depend on the /value/ of the the stored address in any way so that
// we can access it from ordinary code without directly touching
// private data.
template <class Tag>
struct stowed
{
static typename Tag::type value;
};
template <class Tag>
typename Tag::type stowed<Tag>::value;
// Generate a static data member whose constructor initializes
// stowed<Tag>::value. This type will only be named in an explicit
// instantiation, where it is legal to pass the address of a private
// member.
template <class Tag, typename Tag::type x>
struct stow_private
{
stow_private() { stowed<Tag>::value = x; }
static stow_private instance;
};
template <class Tag, typename Tag::type x>
stow_private<Tag,x> stow_private<Tag,x>::instance;
// ------- Usage -------
// A demonstration of how to use the library, with explanation
struct A
{
A() : x("proof!") {}
private:
char const* x;
};
// A tag type for A::x. Each distinct private member you need to
// access should have its own tag. Each tag should contain a
// nested ::type that is the corresponding pointer-to-member type.
struct A_x { typedef char const*(A::*type); };
// Explicit instantiation; the only place where it is legal to pass
// the address of a private member. Generates the static ::instance
// that in turn initializes stowed<Tag>::value.
template class stow_private<A_x,&A::x>;
int main()
{
A a;
// Use the stowed private member pointer
std::cout << a.*stowed<A_x>::value << std::endl;
};
@ProExpertProg
Copy link

This makes sense, thank you! I forgot that static members in classes are just declarations and need definitions.

@YunHsiao
Copy link

YunHsiao commented Mar 9, 2024

Here's a even more straightforward implementation, with better encapsulations & use cases:
https://github.com/YunHsiao/UnrealSourceInjector/blob/main/SourcePatch/Runtime/Core/Public/Misc/PrivateAccessor.h

@dfrib
Copy link

dfrib commented Mar 9, 2024

@YunHsiao As of new C++20 rules (P0692R1) you can make this even more straightforward, using specialization instead of explicit instantiation definitions. See https://github.com/dfrib/accessprivate (companion article: A foliage of folly).

@YunHsiao
Copy link

YunHsiao commented Mar 12, 2024

@dfrib Great write up on the subject, plus your usage of auto non-type template arguments feature yields much simpler declaration!

Although I'm writing a code injector for different versions of Unreal Engine here so C++14 back compat is a must :(

But besides that, afaic it was a perfectly valid usage of this, which provided some really interesting leverages for us.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment