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 A
s 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 NodeofBook
members.
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:
- API // Method/Type visible to the application programmer
- public // Method/Type visible to your whole library package, but NOT to the api user
- protected // Method/Type visible only to subclasses of the class where it is defined
- 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
How to Load Bmp File Using X11 Window Background
How to Initialize All Tuple Elements by the Same Arguments
Could We Use Extern "C" in C File Without #Ifdef _Cplusplus
Access Violation Writing Location 0Xcccccccc
C++ Error on Ms Visual Studio: "Windows Has Triggered a Breakpoint in Javaw.Exe"
Thread Safety of Matlab Engine API
What's the Difference Between Cout<<Cout and Cout<<&Cout in C++
Round to Nearest Multiple of a Number
Do You Prefer Explicit Namespaces or 'Using' in C++
Getting Errors While Compiling
Accessing Same-Type Inactive Member in Unions
What Is the Rule That Allows 'This->' to Access Members of Dependent Base Classes
Std::Locale Breakage on MACos 10.6 with Lang=En_Us.Utf-8
Why Is It Not Possible to Overload the Ternary Operator
Running a Windows Program and Detect When It Ends with C++
Add Library Search Path to Clang