Topic: Restricted access for friends?
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Wed, 25 Jan 1995 15:42:31 GMT Raw View
david@atl-intl.com writes:
>BTW, I [...] would
>very much like to be able to use "protected" in inheritance, as in
>class Derived: protected Base ..., in addition to the current "private" and
>"public."
You can already do that. In fact as far as I know you could always do
that (ever since the language had "protected").
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
all [L] (programming_language(L), L \= "Mercury") => better("Mercury", L) ;-)
Author: david@atl-intl.com
Date: Sun, 22 Jan 1995 00:53:18 UNDEFINED Raw View
In article <HUFFMAN.95Jan17135243@acc222.ist.vf.ge.com>
huffman@acc222.ist.vf.ge.com (Huffman Robert) writes:
>I keep wishing I could somehow keep friends from accessing the private
>data members of a class. In other words, I would like to allow a
>friend to have access to protected members, just like a publically
>inherited subclass. So, why isn't there a construct something like
>the following?
>For the sake of symmetry, this extension would probably allow the
>declaration of a "private friend" which would behave exactly as
>friends currently behave.
My one suggest a new word, "associate," which would seem to convey
the relationship you suggest? BTW, I do like the idea, and also would
very much like to be able to use "protected" in inheritance, as in
class Derived: protected Base ..., in addition to the current "private" and
"public."
But then again, since I do not write the compilers, just use them, I do
not know how much my voice counts.
Author: jason@cygnus.com (Jason Merrill)
Date: Wed, 25 Jan 1995 20:22:43 GMT Raw View
>>>>> Fergus Henderson <fjh@munta.cs.mu.OZ.AU> writes:
> david@atl-intl.com writes:
>> BTW, I [...] would
>> very much like to be able to use "protected" in inheritance, as in
>> class Derived: protected Base ..., in addition to the current "private" and
>> "public."
> You can already do that. In fact as far as I know you could always do
> that (ever since the language had "protected").
No, not that long. It wasn't in the ARM.
Jason
Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Thu, 26 Jan 1995 10:08:15 GMT Raw View
In article <MATT.95Jan22121304@physics7.berkeley.edu> matt@physics.berkeley.edu writes:
>In article <3fsmm2$r68@engnews2.Eng.Sun.COM> clamage@Eng.Sun.COM (Steve Clamage) writes:
>
>That's true, except that it sort of begs the question: why shouldn't
>there be something sort of like a friend, but that isn't conceptually
>the same as a public member function? That is, why shouldn't it
>be possible to selectively export certain features of a class,
>while leaving other features private?
There are two reasons I can think of. The first is
excessive complexity. The second is excessive coupling.
Point 1 is that it will be a lot more work to figure out
who to give access to what, for very little benefit.
Point 2 is more serious. Giving a friend access to
just some private details and not others means that modifying
the private interface of the class -- or the implementation of
the friend -- is likely to require changing _more_ code.
The basic notion is that a finite set of methods
maps the private state to the public state; this map is called
the representation. Providing a method _of_ the representation
with access to only part of the representation does not make
a lot of sense to me. Changing the representation requires
changing the implementations of all the methods with access.
If you _really_ want a friend with limited access,
you can have one. You just make a "viewer" class, which
can be done with delegation, and forward the selected
methods to it.
For example:
class A {
int x;
int y;
public:
friend A::B::B(A&); // will this work? Forward reference?
class B {
int &x;
friend void f(A&);
B(A &a) : x(a.x) {}
};
};
void f(A &a) {
a.x; // I'm not a friend of A
a.y; // I'm not a friend of A
B b(a); // I _am_ a friend of B
b.x++; // Now I can modify A::x, but not A::y
}
Class B has a private constructor and so can be constructed
_only_ by its friends. It provides _its_ friends with access to
a specific selected part of the representation of A.
The constructor of B is a friend of A, to allow B to access the
representation -- in fact, B could be made a friend, it is
quite trusted, being nested in A.
If you think about it, this technique is much more powerful
than merely providing access to selected features, or
allowing selected features to be accessed by selected
methods. You can _remap_ the (private) interface of the class
and provide controlled access in almost any way you want.
Wnat to provide access to selected objects? No problem.
Keep a list of their pointers in the access server object
and throw an exception if a request is made by an unlicenced
client.
Summary: I believe the C++ access control mechanism is adequate.
It has some deficiencies, the worst of which, in my opinion,
is not allowing one to provide public members which can be
marked as having _no_ access. Such members just call other
public member functions: they could, in fact, be globals;
but are not because:
1) programmers have weird ideas about polluting the
global namespace (silly)
2) C programmers hate LISP (lots of nested brackets)
and like infix (reasonble)
3) Exactly which functions have or need access may
properly be an implementation detail.
(Pointed out to me by Andrew Koenig, who is
almost always right)
In other words, there are two kinds of protection:
1) granting of access to a method
2) requesting/denying a need for access by a method
A function not needing to modify an object announces its
requirements by
f(T const *t) // I do not need to modify the object t denotes
A _member_ function should be able to announce it does not need access
_in the implementation of the member_ just so the compiler can catch
unnecessary access to representation details.
What this gives you is a much smaller set of functions that
_do_ in fact need to be modified if the representation is changed.
While still allowing you to "nest" the function in a class.
A large commercial class may have hundreds of members, many of
which do not in fact need access. At present, an unenforcible
comment is the best you can do.
BTW: well, if this is the worst deficiency of the access protection
mechanism, I can live with it as it is :-)
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd,
81A Glebe Point Rd, GLEBE Mem: SA IT/9/22,SC22/WG21
NSW 2037, AUSTRALIA Phone: 61-2-566-2189
Author: matt@physics7.berkeley.edu (Matt Austern)
Date: 22 Jan 1995 20:13:04 GMT Raw View
In article <3fsmm2$r68@engnews2.Eng.Sun.COM> clamage@Eng.Sun.COM (Steve Clamage) writes:
> Properly viewed, a friend function is part of the public interface
> of a class. It is conceptually the same as a public member function,
> except that for one reason or another, it cannot or should not have
> a "this" parameter.
That's true, except that it sort of begs the question: why shouldn't
there be something sort of like a friend, but that isn't conceptually
the same as a public member function? That is, why shouldn't it
be possible to selectively export certain features of a class,
while leaving other features private?
My use of the words "export" and "feature" are probably a tip-off
about what I'm thinking about, which is Eiffel's way of handling
protection. It's much more general, and much more fine-grained, than
C++'s public/protected/private mechanism. For each member function or
member variable, you can specify which classes are able to access it;
this can be ANY (in which case it's the same as what C++ calls
public), or NONE (in which case those features aren't even accessible
to other objects of the same class), or anything in between.
There are some things you can do with C++'s protection mechanism that
you can't do with Eiffel's. In general, though, I think that Eiffel
gets it right. The public/protected/private specification is too
coarse-grained: it should be possible for features to be public from
the perspective of one class and private from the perspective of
another.
--
--matt
Author: Michael Cook <mcook@cognex.com>
Date: 23 Jan 1995 15:25:16 GMT Raw View
>>>>> "matt" == Matt Austern <matt@physics7.berkeley.edu> writes:
matt> There are some things you can do with C++'s protection mechanism that
matt> you can't do with Eiffel's. In general, though, I think that Eiffel
matt> gets it right. The public/protected/private specification is too
matt> coarse-grained: it should be possible for features to be public from
matt> the perspective of one class and private from the perspective of
matt> another.
The C++ language already supports "selective exporting".
Here's an example:
class A
{
public:
class K { friend class KF; private: K(){} };
void k(const K&);
class J { friend class JF; private: J(){} };
void j(const J&);
class I { friend class IF; private: I(){} };
void i(const I&);
};
Only class KF can invoke `A::k()', because only KF has permission to create
the "key" object `A::K'. The key object is never actually used for anything
except compile-time checking of permissions.
Similarly, only class JF can invoke `A::j()', and only class IF can invoke
`A::i()'.
--
Michael Cook <mcook@cognex.com>
Cognex Corporation, One Vision Drive, Natick, Massachusetts 01760-2059
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Tue, 24 Jan 1995 10:29:29 GMT Raw View
Michael Cook <mcook@cognex.com> writes:
>The C++ language already supports "selective exporting".
There's a difference between being able to do something in a language
and the language supporting that feature. You can do OOP in C, but
C doesn't support OOP. Similarly, you can hack up something
equivalent to selective exporting in C++, but I wouldn't say C++
supports selective exporting.
>Here's an example:
>
> class A
> {
> public:
> class K { friend class KF; private: K(){} };
> void k(const K&);
Even better, use a default argument:
class K { friend class KF; private: K(){} };
void k(const K& = K());
then the hack is confined to the class declaration; in KF, you
can just use `A a; a->k()'.
But even then, is the hack really worth it? In the long run, it might
be more maintainable if you just made the member public.
--
Fergus Henderson - fjh@munta.cs.mu.oz.au
all [L] (programming_language(L), L \= "Mercury") => better("Mercury", L) ;-)
Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 22 Jan 1995 04:24:34 GMT Raw View
huffman@acc222.ist.vf.ge.com (Huffman Robert) writes:
>I keep wishing I could somehow keep friends from accessing the private
>data members of a class. In other words, I would like to allow a
>friend to have access to protected members, just like a publically
>inherited subclass.
We just had this discussion last week.
Properly viewed, a friend function is part of the public interface
of a class. It is conceptually the same as a public member function,
except that for one reason or another, it cannot or should not have
a "this" parameter.
No one ever suggests restricting access of member functions, yet
that is logically the same thing. (And equally pointless, in my view.)
You can simulate what you want, however, by adding another class.
("Every problem in computer science can be solved by adding a
level of indirection.")
Given:
class X { friend int f(int); ... };
Change the name of X to X_base, and make a new X:
class X_base { ... }; // same as X above, but no friends
class X : public X_base { friend int f(int); ... };
Now function f has access to the public and protected members
of X_base, but not to the private members. You never create any
X_base objects or pointers, but just use X as before.
I still don't know why anyone would want to bother, however.
--
Steve Clamage, stephen.clamage@eng.sun.com
Author: huffman@acc222.ist.vf.ge.com (Huffman Robert)
Date: Tue, 17 Jan 1995 18:52:43 GMT Raw View
I keep wishing I could somehow keep friends from accessing the private
data members of a class. In other words, I would like to allow a
friend to have access to protected members, just like a publically
inherited subclass. So, why isn't there a construct something like
the following?
class Bar{};
class Foo
{
protected friend class Bar;
protected:
void BarCanSeeThis();
private:
void BarCannotSeeThis();
}
For the sake of symmetry, this extension would probably allow the
declaration of a "private friend" which would behave exactly as
friends currently behave.
You might also allow the compilation of "public friend", but it would
be a little non-sensical, accomplishing no more than informing
users that the class collaborates with the public friend, but that the
public friend has no special access privileges.
The use of a "protected friend" would provide for better
encapsulation, since implementation details could still be hidden,
even from friends, in the private part of a class. And, though I'm no
compiler writer, I do not think it would be exceptionally difficult to
implement.
So, what do the experts think? Would such an extension be
appropriate?
--
//=====================================================================
// Robert Huffman Martin Marietta
// huffman.robert@ist.vf.ge.com Information Systems and Technologies
// tel: +(1) (610) 992-6655 640 Freedom Business Center
// fax: +(1) (610) 992-6299 King of Prussia, PA (USA) 19406
//=====================================================================