Rephrasing the problem a bit:
- I have an instance of
MySpecialObject
- an instance of
JLP
wants to call the methods of MySpecialObject
- an instance of
BEV
wants to read the public data of MySpecialObject
- the instance of JLP shouldn't be able to read public data and the
BEV
shouldn't be able to call member functions
This should be as type-safe as possible.
A solution I see involves wrappers :)
- you write the code for
MySpecialObject
as you would normally, ignoring this extra requirement
- you write a wrapper for each aspect of your class you wish to restrict. Say,
MySpecialObject_Read
and MySpecialObject_Execute
.
- these wrappers forward the requests (method calls, getter/setters) to an underlying
shared_ptr
of MySpecialObject
- your
MySpecialObject
, MySpecialObject_Read
and MySpecialObject_Execute
classes each have (as needed) a "convert to ..." method. This method returns an appropriate wrapper over the underlying MySpecialObject
This solution provides a type-safe accessor with the desired limitations.
Each client class can choose what kind of access it needs.
(And since you write these classes, you know what access you need.)
If that is not acceptable, you could add factories that only create wrappers with certain limitations depending on a "token". That token might be the RTTI information of the calling class instance, although this could be abused.
Does this solve the original problem?
EDIT:
Remember that since you are the programmer you can instantiate an A
whenever you want. By adding your class to a friend
list or whatever...
What this solution provides is a clearer interface. Removing the explicit conversions probably makes it safer but less flexible. But, since they are explicit, you can easily look for them in the code and treat them as signs your architecture has a flaw somewhere.
Specifically, you can have code like this:
shared_ptr<A> * a = new A(parameters);
A_read aRead(a);
A_execute aExec(a);
A_write aWrite(aExec);
logger->Log(aRead);
view->SetUserData(aWrite);
controller->Execute(aExec);
Here there is an explicit conversion between an execute wrapper and a write wrapper, but you can decide on this based on your specific requirements.
But, with little effort (knowing which conversions are valid), just by looking at the call locations you can see that (with confidence!):
- the
logger
will not change the state of your A
- the
view
will not call methods on your A
(other than setters)
This is true even if those particular method calls end up calling hundreds of other methods, more than you'd like to examine by hand.
At the cost of a few thin wrappers you gain the ability to see at a glance what a particular function call will do with the parameters you send. This may help a lot during debugging by helping you eliminate some branches from your investigation and, in general, would help people trying to understand the program.
I couldn't really find other reasons for using this ACL idea, at least ones where the costs don't outweigh the benefits. However, it does seem more intuitive than the visitor solution mentioned in the other answer.
Best Answer
allow me to check at one look what member variables are used
Using a method signature solely to identify members of a class is a crude, non-OO style of programming. OOP is about higher level abstractions and relationships. If you are having trouble tracking a ridiculous # of members, then you should immediately review your classes to ensure they have a single and easily identifiable purpose. This sounds like you are constructing god objects.
Also, a change in code by removing a particular member variable can break **many** functions.
A great indicator of tight coupling. Decouple your classes. Look at dependency injection..
allow me to supply other values for tests and debugging.
Unclear on meaning here. Especially because you go on to say
In this case however, the private function remains isolated am I can still call it using other values without fixing the function.
Generally, private functions make code more difficult to (unit) test not easier. Are you familiar with Mocking? Are you testing with unit tests, some kind of home brew or other?