Allowing Access to Private Members

Allowing access to private members

The blog post and its code is unfortunately a bit unclear. The concept is simple: an explicit template instantiation gets a free backstage pass to any class, because

  • An explicit instantiation of a library class may be an implementation detail of a client class, and
  • Explicit instantiations may only be declared at namespace scope.

The natural way to distribute this backstage pass is as a pointer to member. If you have a pointer to a given class member, you can access it in any object of that class regardless of the access qualification. Fortunately, pointer-to-members can be compile-time constants even in C++03.

So, we want a class which generates a pointer to member when it's explicitly instantiated.

Explicit instantiation is just a way of defining a class. How can merely generating a class do something? There are two alternatives:

  • Define a friend function, which is not a member of the class. This is what litb does.
  • Define a static data member, which gets initialized at startup. This is my style.

I'll present my style first, then discuss its shortcoming, and then modify it to match litb's mechanism. The end result is still simpler than the code from the blog.

Simple version.

The class takes three template arguments: the type of the restricted member, its actual name, and a reference to a global variable to receive a pointer to it. The class schedules a static object to be initialized, whose constructor initializes the global.

template< typename type, type value, type & receiver >
class access_bypass {
static struct mover {
mover()
{ receiver = value; }
} m;
};

template< typename type, type value, type & receiver >
typename access_bypass< type, value, receiver >::mover
access_bypass< type, value, receiver >::m;

Usage:

type_of_private_member target::* backstage_pass;
template class access_bypass <
type_of_private_member target::*,
& target::member_name,
backstage_pass
>;

target t;
t.* backstage_pass = blah;

See it work.

Unfortunately, you can't rely on results from this being available for global-object constructors in other source files before the program enters main, because there's no standard way to tell the compiler which order to initialize files in. But globals are initialized in the order they're declared, so you can just put your bypasses at the top and you'll be fine as long as static object constructors don't make function calls into other files.

Robust version.

This borrows an element from litb's code by adding a tag structure and a friend function, but it's a minor modification and I think it remains pretty clear, not terribly worse than the above.

template< typename type, type value, typename tag >
class access_bypass {
friend type get( tag )
{ return value; }
};

Usage:

struct backstage_pass {}; // now this is a dummy structure, not an object!
type_of_private_member target::* get( backstage_pass ); // declare fn to call

// Explicitly instantiating the class generates the fn declared above.
template class access_bypass <
type_of_private_member target::*,
& target::member_name,
backstage_pass
>;

target t;
t.* get( backstage_pass() ) = blah;

See it work.

The main difference between this robust version and litb's blog post is that I've collected all the parameters into one place and made the tag structure empty. It's just a cleaner interface to the same mechanism. But you do have to declare the get function, which the blog code does automatically.

Accessing private members of a class from another class

You have multiple possibilities to access members of other classes.

If a member is private (as in your case) you can either declare other classes as a friend of this class or write getters and setters.

Method 1: Getters and Setters

class A {
private:
int a;
public:
int GetA() { return a; }
void SetA(int newA) { a = newA; }
};

This however will grant access to your private data from every other place in your code. Though you can leave setA away causing only read access to the private a.


Edit:

As @tobi303 has correctly pointed out: Returning a raw pointer via a getter (as it would be in your case) is probably not a good idea. So I would recommend in this case to either return the object the pointer points to or use smart pointers like std::shared_ptr and return them:

class {
private:
int *a;
std::shared_ptr<int> b;
public:
int getA() { return a ? *a : 0; } // only dereference the pointer if it points somewhere
std::shared_ptr<const int> getB() { return b; } // return as std::shared_ptr<const int> to prevent indirect write access to a
};

Method 2: Friend Classes

class B
{};

class A {
private:
int a;
public:
friend class B;
};

In this case only B and A can access the private data of A. You can also grant access to the private data to only a few functions.

However, granting write access to private members often indicates a flaw in your design. Maybe they should be public (see Method 3) or you don't even need write access and just reading them would be completely sufficient for your needs.

Method 3: Public Members

class A {
public:
int a;
};

Similar to Method 1 (with both the getter and the setter) you are now granting read and write access to As member a.

If you really need read and write access to a private member, Method 2 is the way to go. But as I've said: Think about your design once again, do you really need this?

Can I access private members from outside the class without using friends?

If the class contains any template member functions you can specialize that member function to suit your needs. Even if the original developer didn't think of it.

safe.h

class safe
{
int money;

public:
safe()
: money(1000000)
{
}

template <typename T>
void backdoor()
{
// Do some stuff.
}
};

main.cpp:

#include <safe.h>
#include <iostream>

class key;

template <>
void safe::backdoor<key>()
{
// My specialization.
money -= 100000;
std::cout << money << "\n";
}

int main()
{
safe s;
s.backdoor<key>();
s.backdoor<key>();
}

Output:

900000
800000

Friend class in C++ not allowing access to private member attributes

NodeofBook declaring that ListofBooks is a friend class just means that the implementation of ListofBooks can access NodeofBook's private members, but there still needs to be an instance of NodeofBook to access. Its members are not static; non-static member variables are part of some object. That is, just because the ListofBooks is a friend of NodeofBook does not mean that it magically has instances of NodeofBookmembers.

A friend relationship is not an is-a relationship like inheritance: it is just about access.

GCC allows access to private static member

This definitely looks like a bug since whether it's an instantiated template function or a real function should have no bearing on accessibility of private members in the base class. If you change your code to:

int bar(int&) {
return PRIVATE;
}

then it rightly complains:

testprog.cpp: In member function 'int Derived::bar(int&)':
testprog.cpp:3:26: error: 'constexpr const int Base::PRIVATE' is private
static constexpr int PRIVATE = 1;
^
testprog.cpp:9:16: error: within this context
return PRIVATE;
^

I would just raise this as a bug on gcc. If they do have a different view on its validity, they will let you know about it.

And, for when you do file the bug, I'd suggest using the absolute minimalist example that works, it'll make it much easier for them to debug. I got that down to:

class Base {
static constexpr int PRIVATE = 42;
};
struct Derived : public Base {
template <class T> int bar(T) {
return PRIVATE;
}
};
int main() {
Derived d;
return d.bar(1);
}

You may also want to indicate the various possibilities for declaring PRIVATE and their effect on gcc and clang (trunks as of this question):

                                gcc       clang
-------- --------
static constexpr int accepted rejected
static const int accepted rejected
const int rejected rejected
int rejected rejected

Using a non-templated function instead (as mentioned above):

int bar(int) {
return PRIVATE;
}

seems to result in gcc "behaving" itself:

                                gcc       clang
-------- --------
static constexpr int rejected rejected
static const int rejected rejected
const int rejected rejected
int rejected rejected

So, if this is indeed a gcc problem, I'd be thinking that there's some interaction between static and templates which is causing the issue.

C++: Allowing Access to Protected Members of Class and not Private Members

It's not elegant, but this might work for you:

class B;

class A {
protected:
int x;
private:
int y;
};

class A_wrapper : public A {
friend B;
};

class B {
public:
A_wrapper a;
int foo() {
a.x; // Ok
a.y; // Compiler error!
}
};

Accessing private members

"Never say never". I'm sure somewhere in the universe, there's a situation that will force you to have to do this...

But I certainly would cringe if I had to do it. You truly need get lots of opinions on your situation before pulling the trigger. Can you describe your specific situation and maybe we could see if it makes sense or what better alternatives might exist?

In response to comment/question--
Define "permissions" -- institutional permission? That sounds like not a programming problem, but something to talk to whoever is asserting said permission. Maybe this is more of a political issue than a technical one? Again, I think we need more specifics--even if it was somewhat about the politics of the situation. That may or may not be deemed out of scope for the website, however.

How to allow global functions access to private members

I usually solve this problem by extracting the application programmer interface in the form of abstract classes, which is the set of types and operations that the application programmer (i.e. the user of your library) will be able to use.

Then, in my implementation, I declare public all methods and types that will be used within my package by other classes.

For example:

  • API: IDevice.h
  • Internal: Device.h Device.cpp

I define the API classes in a way similar to:

class IDevice {
public:
// What the api user can do with the device
virtual void useMe() = 0;
};

Then, in my library (not exposed to user interface):

class Device : public IDevice {
public:
void useMe(); // Implementation

void hiddenToUser(); // Method to use from other classes, but hidden to the user
}

Then, for every header(interface) that is part of the API, i will use the IDevice type instead of the Device type, and when internally i will have to use the Device class, i will just cast the pointer down to Device.

Let's say you need a Screen class that uses the class Device, but is completely hidden to the user (and won't therefore have any API abstract class to implement):

#include "Device.h"
class Screen {
void doSomethingWithADevice( Device* device );
}

// Screen.cpp
void Screen::doSomethingWithADevice( Device* device ){
device->hiddenToUser();
}

This way, you don't have to make something private just because you don't want the user to see/use it. You obtain a further layer of abstraction (1 above public) which I call API. You will have:

  1. API // Method/Type visible to the application programmer
  2. public // Method/Type visible to your whole library package, but NOT to the api user
  3. protected // Method/Type visible only to subclasses of the class where it is defined
  4. private // Method/Type local to the defining class

Therefore, you can declare public methods you need to register as callback method, without the user seeing them.

Finally, I deliver the content of API to the user together with the binary, so that the user will have access exactly to what i explicitly defined in the API and nothing else.



Related Topics



Leave a reply



Submit