 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
fat chat Guest
|
Posted: Mon Nov 14, 2005 9:22 am Post subject: scaling visibility |
|
|
Given two classes A and B, I would like to define in B the access level
"public-only-to-A".
An unsatisfactory solution:
// ================================================================
class A ;
class B {
B& operator=(const B&);
class visible_to_A {
friend class A;
B& owner_;
int b_data() { return owner_.b_private_data_; }
void a_can_call_this() {;}
public:
visible_to_A(B& owner) : owner_(owner) {}
};
friend class visible_to_A;
public:
B() : interface(*this) {}
visible_to_A interface; // public, but only A can do anything with
it.
private:
int b_private_data_;
};
class A {
public:
void access_B(B& b)
{
int bd = b.interface.b_data();
b.interface.a_can_call_this();
}
void mess_things_up(B& b)
{
B tmp;
// b.interface.owner_ = tmp; // operator= is disabled
}
};
int main()
{
A a;
B b;
a.access_B(b);
}
//
=====================================================================
Though straightforward, it seems a bit tedious and roundabout, and does
not scale well e.g. supposing there were several classes like A, with
different and possibly overlapping access requirements for B.
Also, I don't like the fact that B::visible_to_A::owner_ is visible to
A. I disabled the assignment operator for B so that it could not
tampered with, but this imposes a restriction on B which one may not
find acceptable. (Is there any other way it can currently be tampered
with?)
This is probably something many of you have seen before, and I would
welcome any comments on it.
Thanks.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Alberto Ganesh Barbati Guest
|
Posted: Tue Nov 15, 2005 9:21 am Post subject: Re: scaling visibility |
|
|
fat chat wrote:
| Quote: | Given two classes A and B, I would like to define in B the access level
"public-only-to-A".
|
what about:
class A ;
class B_visible_to_A {
int b_private_data_;
friend class A;
};
class B : public B_visible_to_A {
// rest of B
};
a variation to this example (possibly more scalable) could be to exploit
the base-from-member idiom shown here
http://boost.org/libs/utility/base_from_member.html
HTH,
Ganesh
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Alberto Ganesh Barbati Guest
|
Posted: Tue Nov 15, 2005 2:35 pm Post subject: Re: scaling visibility |
|
|
Alberto Ganesh Barbati wrote:
| Quote: | fat chat wrote:
Given two classes A and B, I would like to define in B the access level
"public-only-to-A".
what about:
class A ;
class B_visible_to_A {
int b_private_data_;
friend class A;
};
|
of course, there's a "friend class B;" missing up there ;-)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Greg Herlihy Guest
|
Posted: Wed Nov 16, 2005 6:04 pm Post subject: Re: scaling visibility |
|
|
fat chat wrote:
| Quote: | Given two classes A and B, I would like to define in B the access level
"public-only-to-A".
An unsatisfactory solution:
// ================================================================
class A ;
class B {
B& operator=(const B&);
class visible_to_A {
friend class A;
B& owner_;
int b_data() { return owner_.b_private_data_; }
void a_can_call_this() {;}
public:
visible_to_A(B& owner) : owner_(owner) {}
};
friend class visible_to_A;
public:
B() : interface(*this) {}
visible_to_A interface; // public, but only A can do anything with
it.
private:
int b_private_data_;
};
class A {
public:
void access_B(B& b)
{
int bd = b.interface.b_data();
b.interface.a_can_call_this();
}
void mess_things_up(B& b)
{
B tmp;
// b.interface.owner_ = tmp; // operator= is disabled
}
};
int main()
{
A a;
B b;
a.access_B(b);
}
//
=====================================================================
Though straightforward, it seems a bit tedious and roundabout, and does
not scale well e.g. supposing there were several classes like A, with
different and possibly overlapping access requirements for B.
Also, I don't like the fact that B::visible_to_A::owner_ is visible to
A. I disabled the assignment operator for B so that it could not
tampered with, but this imposes a restriction on B which one may not
find acceptable. (Is there any other way it can currently be tampered
with?)
This is probably something many of you have seen before, and I would
welcome any comments on it.
|
I doubt few clients would be able to negotiate as confusing an
interface as B's, so in that sense B's implementation seems to be in
little danger of being called .
In all seriousness, elaborate schemes to enforce finely-tuned access
requirements are simply not worthwhile. For one, they tend to obfuscate
source code - which ends up doing more harm than good. For another,
they impose needless constraints. Why would clients other than A ever
have a reason to call B's interface, such that it needs such
protection? What disaster is being averted that would justify all this
effort?
Both B's interface and the question about tampering suggest to me that
the purpose of C++'s access controls has been missed - and is being
taken for something that it is not. The most important point to keep in
mind about access controls is that they do not provide any kind of
security. They do not protect any asset, nor do they enforce any right.
C++ developers do not police the use of their classes, and issue fines
or impose other penalties for anyone caught calling a "private" method
from a non-friend, non-member function (or someone will correct me if I
am wrong). Thinking of access controls in adversarial terms - of
securing or tampering - is counterproductive. Access controls really
have just one purpose and a purpose that benefits everyone alike.
Access controls are just a form of documention. They help the client to
understand an interface. The keywords "public" and "private" indicate
which routines are acessible, useful, documented and stable, and those
which are likely to be of no use (for clients), undocumented and
subject to future revision, respectively.
The compiler by checking access levels is doing its part to prevent
programming errors. It is not an agent of the interface's author -
imposing from afar the author's will upon each client. Its purpose is
more benign: it is double-checking that the program is calling that
interface in the recommended manner, and it does so solely for the
benefit of the client. The only one who has anything to lose by
"tampering" with access restrictions, is the one doing the tampering.
That is the reason why access controls can be easily circumvented. And
it is also the reason why access schemes that overcomplicate the
program wind up harming the client's interests more than such systems
advance them.
A client of an interface can be trusted to make sensible choices - even
in the absence of draconian access controls. The author of the
interface simply has to explain its use - through documentation, in
source code and with access restrictions. And even if the client still
makes poor choices despite all of that help, then so be it. There only
so much one can do. Besides, programming wouln't be much fun without
the freedom to make one's own mistakes.
Greg
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|