Topic: Limiting member access of friends


Author: David R Tribble <dtribble@technologist.com>
Date: 1999/03/29
Raw View
Christopher Eltschka wrote:
> David R Tribble wrote:
>> David R Tribble wrote:
>> >> When declaring a friend of a class, it would be nice to be able to
>> >> list the members you want the friend (class or function) to be
>> >> able to access; any member of the class not in the list could not
>> >> be accessed by the friend.
>> >[...]
>> >> This would plug a hole that exists in the type-safety (data
>> >> hiding) mechanism of C++.
>>
>> Valentin Bonnard wrote:
>> > There is no such hole. Friend is not a hole, mainly a way to
>> > avoid such holes.
>>
>> I was referring to the fact that making a class or function a
>> friend of another class automatically grants the friend total access
>> to all members of the second class, private or otherwise.  There is
>> no direct way to limit the friend's access to a restricted set of
>> members.  This is a type-safety hole; granting friendship gives too
>> much access.
>
> There's another "hole" of that type: Every member function
> of a class has access to all private parts of the class, even
> if it should mess only with a part of it. For example, a
> function "inc_ref_count" should obviously only have access
> to the reference count (and possibly related data). However
> it can access everything in that class.
> Again, you can make an indirect solution by moving the
> reference counting to a local class, or by making a base class.
> However, there's no way to _directly_ specify this.
>...
> The situation seems quite similar to yours.
> So would you consider it a hole as well, that you can't restrict
> access for member functions?

The big difference being, of course, that all of the member functions
of the class comprise the implementation of that class.  Since they
implement the operations of the class, it makes sense that they have
unrestricted access to their class object members, whether they
actually access them or not.

In contrast, friend functions are implementations of something else,
particularly if they are member functions of a completely different
class.  They poke into the other class's members from outside that
class's implementation.  It's extremely useful when you really need
it, but it brings with it some risks.

At any rate, none of the counterarguments in this thread convinced
me that limiting member access to friends would be a bad thing.  All
of the arguments either gave suggestions on alternate approaches
that accomplished essentially the same thing, or were aesthetic
arguments positing that restricted member access was "taking things
too far".  No examples were given to demonstrate any harm it causes.

But as I wrote before, I have grown weary of this thread.  Enough
already.

-- David R. Tribble, dtribble@technologist.com --
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/03/30
Raw View
David R Tribble <dtribble@technologist.com> writes:

>At any rate, none of the counterarguments in this thread convinced
>me that limiting member access to friends would be a bad thing.  All
>of the arguments either gave suggestions on alternate approaches
>that accomplished essentially the same thing, or were aesthetic
>arguments positing that restricted member access was "taking things
>too far".  No examples were given to demonstrate any harm it causes.

The implicit, if not explicit, argument was that it complicates
the language to no useful purpose.

There's no end to features that programmers can dream up to
be added to C++. The criterion expressed in D&E and in other
places is that a proposed language addition or change should
solve a serious programming programming problem affecting a wide
range of programs for which there is no good workaround aleady
in the language.

So far, no one seems to agree with you that there is a problem
to solve, let alone a serious one affecting a wide range of programs.

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: stanley@west.sun.com (Stanley Friesen [Contractor])
Date: 1999/03/30
Raw View
In article <36FADBBD.B67CFCE8@technologist.com>,
David R Tribble  <dtribble@technologist.com> wrote:
>
>But you may not have control over the friend functions; you can't
>limit their access to the innards of your class because it's all
>or nothing.

A friend function should be an intrinsic part of the same module as the
class.  No person or organization not involved in maintaining the class
module should ever be editing a friend function.  That is, a friend is
as much part of the interface of a class as a member function.

Ergo, for practical purposes, you have as much control over friends as you
do over member functions.

If you are paranoid, put the friend function definition in the same source
file as one of the key constructors, then nobody can substitute without
major surgery.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: stanley@west.sun.com (Stanley Friesen [Contractor])
Date: 1999/03/31
Raw View
In article <36FFF94C.AC7F6E1C@technologist.com>,
David R Tribble  <dtribble@technologist.com> wrote:
>In contrast, friend functions are implementations of something else,

If they aren't part of the interface, they shouldn't be friends.
Friendship is for those parts of the interface that for syntactical
or functional reasons cannot be implemented effectively as members.

Thus a binary operator that needs to be able to take results of conversions
as the first parameter are a valid use of friends, as they are truly
part of the interface.

All friends should be co-implemented with the classes they are friends of.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: David R Tribble <dtribble@technologist.com>
Date: 1999/03/24
Raw View
David R Tribble wrote:
> >>> When declaring a friend of a class, it would be nice to be able to
> >>> list the members you want the friend (class or function) to be
> >>> able to access; any member of the class not in the list could not
> >>> be accessed by the friend.
> >>[...]
> >>> This would plug a hole that exists in the type-safety (data
> >>> hiding) mechanism of C++.

Valentin Bonnard wrote:
> >> There is no such hole. Friend is not a hole, mainly a way to
> >> avoid such holes.

David Tribble wrote:
> >I was referring to the fact that making a class or function a
> >friend of another class automatically grants the friend total access
> >to all members of the second class, private or otherwise.  There is
> >no direct way to limit the friend's access to a restricted set of
> >members.  This is a type-safety hole; granting friendship gives too
> >much access.

Steve Clamage wrote:
> I don't understand why you consider it a type-safety hole.
> You must grant access explictly. You can't grant access
> accidentally, and the friend cannot grab access without
> your knowing about it. If you want to restrict access,
> don't grant it, or factor your design differently.

Because when you grant friendship, you grant total access.  Limited
friendship would be safer, i.e., it would be a smaller hole.  If
nothing else, it would let the compiler issue errors when your
friend function accidently accessed something you didn't intend it
to.

And it is possible for a bogus friend class to grab access without
my class's knowledge, if the friend class is declared in a different
header file.

> You don't have to make the class a friend. You can make a single
> member function a friend if you want.

This I did not know.  I assume you're saying that the following
is legal then:

    class Bar
    {
    public:
        void    func();
        ...
    };

    class Foo
    {
        friend void  Bar::func();   // Legal (?)
        ...
    };

This is exactly the solution I wanted, but I had assumed that it
was illegal syntax.

> The C++ type system is intended to protect against accidents,
> not against fraud. Complete protection is not possible in a
> language with type casts and pointers.

But it's worthwhile to try, isn't it?

-- David R. Tribble, dtribble@technologist.com --


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Stephen.Clamage@sun.com (Steve Clamage)
Date: 1999/03/24
Raw View
David R Tribble <dtribble@technologist.com> writes:

>Steve Clamage wrote:
>> I don't understand why you consider it a type-safety hole.
>> You must grant access explictly. You can't grant access
>> accidentally, and the friend cannot grab access without
>> your knowing about it. If you want to restrict access,
>> don't grant it, or factor your design differently.

>Because when you grant friendship, you grant total access.

But to me "hole" means something you can fall into accidently.
You have total control over who has access to a class.

Once again, the purpose of access control is to protect
against accidents, not fraud.

...

>> You don't have to make the class a friend. You can make a single
>> member function a friend if you want.

>This I did not know.  I assume you're saying that the following
>is legal then:

>    class Bar
>    {
>    public:
>        void    func();
>        ...
>    };

>    class Foo
>    {
>        friend void  Bar::func();   // Legal (?)
>        ...
>    };

>This is exactly the solution I wanted, but I had assumed that it
>was illegal syntax.

It has always been legal C++. See the ARM page 249, for example.

--
Steve Clamage, stephen.clamage@sun.com


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Marc Girod <girod@stybba.ntc.nokia.com>
Date: 1999/03/25
Raw View
>>>>> "Jim" == Jim Hyslop <jim.hyslop@leitch.com> writes:

Jim> Interesting - here you have proposed a solution to the problem,
Jim> and allow friends limited access to your class - but Steve
Jim> Clamage has taken the opposite viewpoint. He argues that hiding
Jim> part of the class (but not the whole class) from friends
Jim> indicates your class is too complex, and should be broken down.

Jim> OK, now picture us lowly programmers - one giant says "don't do
Jim> it" and another say "this is how to do it" - what's a poor,
Jim> non-guru to do? :-)

Wait a minute: they say the same thing!

If you break the class down, then you'll have some references from the
one to the other.

--
Marc Girod                Hiomo 5/1          Voice:  +358-9-511 23746
Nokia Telecommunications  P.O. Box 320       Mobile: +358-40-569 7954
NWS/NMS/NMS for Data      00045 NOKIA Group  Fax:    +358-9-511 23580
                          Finland            marc.girod@ntc.nokia.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Jim Hyslop <jim.hyslop@leitch.com>
Date: 1999/03/25
Raw View
In article <1ypv5yj804.fsf@mahtan.ntc.nokia.com>,
  Marc Girod <girod@stybba.ntc.nokia.com> wrote:
[snip]
> Jim> OK, now picture us lowly programmers - one giant says "don't do
> Jim> it" and another say "this is how to do it" - what's a poor,
> Jim> non-guru to do? :-)
>
> Wait a minute: they say the same thing!
Not really.

> If you break the class down, then you'll have some references from the
> one to the other.
That was Steve Clamage's approach - break the class down.  Valentin Bonnard's
approach was "leave the class alone, and introduce a key class whose sole
purpose is to allow access to certain portions."

I guess, as with all design decisions, this would have to be evaluated on a
case-by-case basis.  I would probably lean towards Steve's approach, and use
the key class only where necessary.

Jim
Note to recruitment agencies:  I will not refer my friends or colleagues
to you nor do I want to use your services to find me a job.  I stop
reading unsolicited email as soon as I determine it is job-recruitment

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Jim Hyslop <jim.hyslop@leitch.com>
Date: 1999/03/25
Raw View
In article <36F8490E.B7AD3FF2@technologist.com>,
  David R Tribble <dtribble@technologist.com> wrote:
[snip]
> And it is possible for a bogus friend class to grab access without
> my class's knowledge, if the friend class is declared in a different
> header file.
Ah, but the trick is not to declare the friend class in a different header.

Since you have already coupled the two classes together by introducing a
friendship, you can prevent such fraud by putting the two declarations
together. Read John Lakos' book "Large Scale C++ Programming" for more
details.

>
> Steve Clamage wrote:
> > You don't have to make the class a friend. You can make a single
> > member function a friend if you want.
>
> This I did not know.  I assume you're saying that the following
> is legal then:
[snip example]
Yes, it's perfectly fine.

> This is exactly the solution I wanted, but I had assumed that it
> was illegal syntax.
You know what they say - when you assume you make an ASS of U and ME! :-)

> > The C++ type system is intended to protect against accidents,
> > not against fraud. Complete protection is not possible in a
> > language with type casts and pointers.
>
> But it's worthwhile to try, isn't it?

No.  There are far too many routes a determined programmer can take to plug
all the possible holes.  Consider what can be done, as Steve said, with
pointers and casts.  Protect vs. Murphy, not Machiavelli.

Jim
Note to recruitment agencies:  I will not refer my friends or colleagues
to you nor do I want to use your services to find me a job.  I stop
reading unsolicited email as soon as I determine it is job-recruitment

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: David R Tribble <dtribble@technologist.com>
Date: 1999/03/26
Raw View
Steve Clamage wrote:
>> I don't understand why you consider it a type-safety hole.
>> You must grant access explictly. You can't grant access
>> accidentally, and the friend cannot grab access without
>> your knowing about it. If you want to restrict access,
>> don't grant it, or factor your design differently.

David R Tribble <dtribble@technologist.com> writes:
>> Because when you grant friendship, you grant total access.

Steve Clamage wrote:
> But to me "hole" means something you can fall into accidently.
> You have total control over who has access to a class.

But you may not have control over the friend functions; you can't
limit their access to the innards of your class because it's all
or nothing.

> Once again, the purpose of access control is to protect
> against accidents, not fraud.

Exactly.  Eiffel, for instance, takes a more restricted view of
encapsulation and data hiding that C++, allowing you to explicitly
state what class members are accessible to its friends.  That way,
the friend can't fall into the hole of accessing a member it wasn't
intended to.  (Eiffel's approach is restricted enough that classes
do not have access to private members of objects of the same class
type by default; a class must be made a friend of itself in order
to do this.)

> >    class Bar
> >    {
> >    public:
> >        void    func();
> >        ...
> >    };
>
> >    class Foo
> >    {
> >        friend void  Bar::func();   // Legal (?)
> >        ...
> >    };
>
> >This is exactly the solution I wanted, but I had assumed that it
> >was illegal syntax.
>
> It has always been legal C++. See the ARM page 249, for example.

The only drawback to this approach is that class Bar must be
declared prior to Foo's declaration, which might present some
problems (especially if we want to declare a member function of
Foo to be a friend of Bar.)

But enough of this; other posters have answered my original
question.

-- David R. Tribble, dtribble@technologist.com --
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/03/26
Raw View
David R Tribble wrote:

> Exactly.  Eiffel, for instance, takes a more restricted view of
> encapsulation and data hiding that C++, allowing you to explicitly
> state what class members are accessible to its friends.

You should also be able to specify for every member function of T
which member of T it can access. Where do you stop ? You should
also be able to specify which global object a function can use...

And you end up with all the code in the header file, just to
specify what every function can/can't do. (After all, giving
the body of a function is the ultimate level of precise
specification !)

Trying to get maximum security by specifying everything in the
class definition, or in the headers in general is a waste of
time.

My point is that a friend is completly trusted, it's logically
_part_ of your class _implementation_.

--

Valentin Bonnard


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/03/26
Raw View
David R Tribble wrote:
>
> David R Tribble wrote:
> >> When declaring a friend of a class, it would be nice to be able to
> >> list the members you want the friend (class or function) to be
> >> able to access; any member of the class not in the list could not
> >> be accessed by the friend.
> >[...]
> >> This would plug a hole that exists in the type-safety (data
> >> hiding) mechanism of C++.
>
> Valentin Bonnard wrote:
> > There is no such hole. Friend is not a hole, mainly a way to
> > avoid such holes.
>
> I was referring to the fact that making a class or function a
> friend of another class automatically grants the friend total access
> to all members of the second class, private or otherwise.  There is
> no direct way to limit the friend's access to a restricted set of
> members.  This is a type-safety hole; granting friendship gives too
> much access.

There's another "hole" of that type: Every member function
of a class has access to all private parts of the class, even
if it should mess only with a part of it. For example, a
function "inc_ref_count" should obviously only have access
to the reference count (and possibly related data). However
it can access everything in that class.
Again, you can make an indirect solution by moving the
reference counting to a local class, or by making a base class.
However, there's no way to _directly_ specify this.

So, would you want to have an extension which allows to specify
that member functions should only have access to selected
members? Something like:

class X
{
public:
  void inc_ref_count() accesses ref_count;
  // ...
private:
  int ref_count;
  // ... other data, which cannot be accessed by inc_ref_count()
};

The situation seems quite similar to yours.
So would you consider it a hole as well, that you can't restrict
access for member functions?


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Marc Girod <girod@stybba.ntc.nokia.com>
Date: 1999/03/27
Raw View
>>>>> "VB" == Valentin Bonnard <Bonnard.V@wanadoo.fr> writes:

VB> David R Tribble wrote:

>> Exactly.  Eiffel, for instance, takes a more restricted view of
>> encapsulation and data hiding that C++, allowing you to explicitly
>> state what class members are accessible to its friends.

VB> You should also be able to specify for every member function of T
VB> which member of T it can access. Where do you stop ? You should
VB> also be able to specify which global object a function can use...

Indeed.
What Eiffel does there is silly: it just adds a potential for
accidental complexity. There are then many competing ways to express
the same intention.

C++ stops at the level of the class, which is the generic means of
offering support for arbitrary concepts:

  if you find it significant, make it a class

Much cleaner, without loss of expressive power!

Now, for this to be fully true, you shouldn't pay for making more
classes (finer granularity). With current compilers, you unfortunately
commonly do (at least with virtual inheritance).
Also, the continuity of semantics should be guaranteed while splitting
one's classes. Things like the lack of "transmissibility" of friendship
break this.

--
Marc Girod                Hiomo 5/1          Voice:  +358-9-511 23746
Nokia Telecommunications  P.O. Box 320       Mobile: +358-40-569 7954
NWS/NMS/NMS for Data      00045 NOKIA Group  Fax:    +358-9-511 23580
                          Finland            marc.girod@ntc.nokia.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Marc Girod <girod@stybba.ntc.nokia.com>
Date: 1999/03/20
Raw View
Hello David,

>>>>> "DT" == David R Tribble <dtribble@technologist.com> writes:

DT> When declaring a friend of a class, it would be nice to be able to
DT> list the members you want the friend (class or function) to be
DT> able to access; any member of the class not in the list could not
DT> be accessed by the friend.

I disagree with your goal.
This would IMHO impair the purpose of the class concept. I believe
that whatever intention you care to identify, you should be able to
support it with a class.

In particular, you should be able to split your class into several
sub-classes, one of them declaring the specific friendship you want.

This is was should be supported. I admit that it is currently not (at
least in practice).
Some limitations come from restrictions to friendship in relation with
templates.
Other relate to the cost of virtual inheritance, which make it
unaffordable to make such fine-grained mixins.

Best Regards!
Marc

--
Marc Girod                Hiomo 5/1          Voice:  +358-9-511 23746
Nokia Telecommunications  P.O. Box 320       Mobile: +358-40-569 7954
NWS/NMS/NMS for Data      00045 NOKIA Group  Fax:    +358-9-511 23580
                          Finland            marc.girod@ntc.nokia.com


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/03/21
Raw View
David R Tribble wrote:

> When declaring a friend of a class, it would be nice to be able to
> list the members you want the friend (class or function) to be
> able to access; any member of the class not in the list could not
> be accessed by the friend.
[...]
> This would plug a hole that exists in the type-safety (data
> hiding) mechanism of C++.

There is no such hole. Friend is not a hole, mainly a way to
avoid such holes.

Sometimes I want to allow a class (and only this class) to call
some functions (for example to give it access to a registery).

One way to do that is to only give this class ctor a pointer
or reference to the registery, but this isn't allways possible
(when the register and remove functions are part of another
class). In this case I use a private key:

class Granting
{
public:
    class Key
    {
        friend class Privilegded;
        Key () {}
        Key (const Key&) {}
    };

    void sensitive_function (Key);
};

class Priviledge
{
public:
    void do_stuff ()
    { g.sensitive_function (Granting::Key ()); }
private:
    Granting& g;
};

Priviledge isn't a friend of Granting, not even close; but
it can do more than another class or free function.

--

Valentin Bonnard


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: David R Tribble <dtribble@technologist.com>
Date: 1999/03/23
Raw View
David R Tribble wrote:
>> When declaring a friend of a class, it would be nice to be able to
>> list the members you want the friend (class or function) to be
>> able to access; any member of the class not in the list could not
>> be accessed by the friend.
>[...]
>> This would plug a hole that exists in the type-safety (data
>> hiding) mechanism of C++.

Valentin Bonnard wrote:
> There is no such hole. Friend is not a hole, mainly a way to
> avoid such holes.

I was referring to the fact that making a class or function a
friend of another class automatically grants the friend total access
to all members of the second class, private or otherwise.  There is
no direct way to limit the friend's access to a restricted set of
members.  This is a type-safety hole; granting friendship gives too
much access.

Steve Clamage wrote:
> If you see this as a problem needing a solution, I would look
> first at your design.
>
> Data hiding should represent functionality, class granularity
> should also represent functionality, and friends should be regarded
> as part of the implementation of the class.
>
> If a friend is not part of the implementation, perhaps your
> design is out of control and you need to review it.
>
> If you need to hide part of the class implementation from other
> parts of its implementation, the class is too complex.  Probably
> you should divide the class into smaller classes, each a logical
> unit, and declare friends accordingly.

I had a very simple need: I wanted a member function of class Foo
to be able to call a private member function of class Bar (e.g.,
Foo::f() could call Bar::g(), which contained all the know-how of the
operation involved) without compromising the data hiding of class
Foo.  By making Foo a friend of Bar, I can do precisely this.  But
the drawback it that Bar has total access to Foo members.  Worse, if
I declare Foo and Bar in different header files, an unscrupulous
programmer can include foo.h and define his own class Bar, exploiting
this total access.

Christopher Eltschka <celtschk@physik.tu-muenchen.de>, Dean Foster
<foster@compstat.wharton.upenn.edu>, and Valentin Bonnard
<Bonnard.V@wanadoo.fr> actually gave workable examples of how to do
what I needed by using intermediate (indirect) classes.  Thank you.

But I stand by my original statement that there is no DIRECT way
to limit friendship.  Other languages, notably Eiffel, do have
such mechanisms.  I was simply suggesting that it might be useful
for C++ to have such a mechanism.

-- David R. Tribble, dtribble@technologist.com --


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Stephen.Clamage@sun.com (Steve Clamage)
Date: 1999/03/23
Raw View
David R Tribble <dtribble@technologist.com> writes:


>David R Tribble wrote:
>>> When declaring a friend of a class, it would be nice to be able to
>>> list the members you want the friend (class or function) to be
>>> able to access; any member of the class not in the list could not
>>> be accessed by the friend.
>>[...]
>>> This would plug a hole that exists in the type-safety (data
>>> hiding) mechanism of C++.

>Valentin Bonnard wrote:
>> There is no such hole. Friend is not a hole, mainly a way to
>> avoid such holes.

>I was referring to the fact that making a class or function a
>friend of another class automatically grants the friend total access
>to all members of the second class, private or otherwise.  There is
>no direct way to limit the friend's access to a restricted set of
>members.  This is a type-safety hole; granting friendship gives too
>much access.

I don't understand why you consider it a type-safety hole.
You must grant access explictly. You can't grant access
accidentally, and the friend cannot grab access without
your knowing about it. If you want to restrict access,
don't grant it, or factor your design differently.

>Steve Clamage wrote:
>> If you see this as a problem needing a solution, I would look
>> first at your design.
>>
>> Data hiding should represent functionality, class granularity
>> should also represent functionality, and friends should be regarded
>> as part of the implementation of the class.
>>
>> If a friend is not part of the implementation, perhaps your
>> design is out of control and you need to review it.
>>
>> If you need to hide part of the class implementation from other
>> parts of its implementation, the class is too complex.  Probably
>> you should divide the class into smaller classes, each a logical
>> unit, and declare friends accordingly.

>I had a very simple need: I wanted a member function of class Foo
>to be able to call a private member function of class Bar (e.g.,
>Foo::f() could call Bar::g(), which contained all the know-how of the
>operation involved) without compromising the data hiding of class
>Foo.  By making Foo a friend of Bar, I can do precisely this.  But
>the drawback it that Bar has total access to Foo members.

You don't have to make the class a friend. You can make a single
member function a friend if you want. That couples the classes to
some extent, but once you grant friendship you have coupled the
classes anyway.

>Worse, if
>I declare Foo and Bar in different header files, an unscrupulous
>programmer can include foo.h and define his own class Bar, exploiting
>this total access.

The C++ type system is intended to protect against accidents,
not against fraud. Complete protection is not possible in a
language with type casts and pointers.

--
Steve Clamage, stephen.clamage@sun.com


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Jim Hyslop <jim.hyslop@leitch.com>
Date: 1999/03/24
Raw View
In article <36F442AB.6A7F@wanadoo.fr>,
  Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
[snip]
> Sometimes I want to allow a class (and only this class) to call
> some functions (for example to give it access to a registery).
>
> One way to do that is to only give this class ctor a pointer
> or reference to the registery, but this isn't allways possible
> (when the register and remove functions are part of another
> class). In this case I use a private key:

Interesting - here you have proposed a solution to the problem, and allow
friends limited access to your class - but Steve Clamage has taken the
opposite viewpoint.  He argues that hiding part of the class (but not the
whole class) from friends indicates your class is too complex, and should be
broken down.

OK, now picture us lowly programmers - one giant says "don't do it" and
another say "this is how to do it" - what's a poor, non-guru to do? :-)

[snip]

Jim
Note to recruitment agencies:  I will not refer my friends or colleagues
to you nor do I want to use your services to find me a job.  I stop
reading unsolicited email as soon as I determine it is job-recruitment

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: David R Tribble <dtribble@technologist.com>
Date: 1999/03/19
Raw View
When declaring a friend of a class, it would be nice to be able to
list the members you want the friend (class or function) to be
able to access; any member of the class not in the list could not
be accessed by the friend.

For example, we could use a syntax like that shown at [B]:

    class Foo
    {
    private:
        int     x;
        int     y;
        int     g();
        void    g(int i);

        friend class Bob;       // [A] existing syntax
        friend class Bar =      // [B] proposed syntax
            x, g(int);
    };

    class Bob
    {
        int     f();    // can access all members of Foo
    };

    class Bar
    {
        int     f();    // can access Foo::x & Foo::g(int) only
    };

Such a notation (shown at [B]) would allow us to explicity limit
the members of Foo that the member functions of class Bar can
access.  (The existing syntax shown at [A] would still mean "export
all members of Foo to friend class Bar".)

This would plug a hole that exists in the type-safety (data
hiding) mechanism of C++.

-- David R. Tribble, dtribble@technologist.com --


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Stephen.Clamage@sun.com (Steve Clamage)
Date: 1999/03/19
Raw View
David R Tribble <dtribble@technologist.com> writes:

>When declaring a friend of a class, it would be nice to be able to
>list the members you want the friend (class or function) to be
>able to access; any member of the class not in the list could not
>be accessed by the friend.

>For example, we could use a syntax like that shown at [B]:

>    class Foo
>    {
>    private:
>        int     x;
>        int     y;
>        int     g();
>        void    g(int i);

>        friend class Bob;       // [A] existing syntax
>        friend class Bar =      // [B] proposed syntax
>            x, g(int);
>    };

>    class Bob
>    {
>        int     f();    // can access all members of Foo
>    };

>    class Bar
>    {
>        int     f();    // can access Foo::x & Foo::g(int) only
>    };

>Such a notation (shown at [B]) would allow us to explicity limit
>the members of Foo that the member functions of class Bar can
>access.  (The existing syntax shown at [A] would still mean "export
>all members of Foo to friend class Bar".)

>This would plug a hole that exists in the type-safety (data
>hiding) mechanism of C++.

If you see this as a problem needing a solution, I would look
first at your design.

Data hiding should represent functionality, class granularity
should also represent functionality, and friends should be regarded
as part of the implementation of the class.

If a friend is not part of the implementation, perhaps your
design is out of control and you need to review it.

If you need to hide part of the class implementation from other
parts of its implementation, the class is too complex.  Probably
you should divide the class into smaller classes, each a logical
unit, and declare friends accordingly.

--
Steve Clamage, stephen.clamage@sun.com


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: David R Tribble <dtribble@technologist.com>
Date: 1999/03/19
Raw View
When declaring a friend of a class, it would be nice to be able to
list the members you want the friend (class or function) to be
able to access; any member of the class not in the list could not
be accessed by the friend.

For example, we could use a syntax like that shown at [B]:

    class Foo
    {
    private:
        int     x;
        int     y;
        int     g();
        void    g(int i);

        friend class Bob;       // [A] existing syntax
        friend class Bar =      // [B] proposed syntax
            x, g(int);
    };

    class Bob
    {
        int     f();    // can access all members of Foo
    };

    class Bar
    {
        int     f();    // can access Foo::x & Foo::g(int) only
    };

Such a notation (shown at [B]) would allow us to explicity limit
the members of Foo that the member functions of class Bar can
access.  (The existing syntax shown at [A] would still mean "export
all members of Foo to friend class Bar".)

This would plug a hole that exists in the type-safety (data
hiding) mechanism of C++.

-- David R. Tribble, dtribble@technologist.com --
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Dean Foster <foster@compstat.wharton.upenn.edu>
Date: 1999/03/19
Raw View
I can't remimber where I saw this solution to this problem, but here is a way
that stays within existing C++ rules.

class Foo
{
class Public_interface
  {
    void g(int i){Foo_g(int i);};
    friend class Bar;
  };
private:
  int x;
  int y;
  int  Foo_g();
  void Foo_g(int);
};


Now class Bar can get at Foo::Public_interface::g, but can't get at anythhing
else in Foo.  Is this clean enough for you?

later,

dean


p.s.  With appropiate scoping, Foo_g and g could have the same name, but I
couldn't remimber the syntax.  :-)
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/03/19
Raw View
David R Tribble wrote:
>
> When declaring a friend of a class, it would be nice to be able to
> list the members you want the friend (class or function) to be
> able to access; any member of the class not in the list could not
> be accessed by the friend.
>
> For example, we could use a syntax like that shown at [B]:
>
>     class Foo
>     {
>     private:
>         int     x;
>         int     y;
>         int     g();
>         void    g(int i);
>
>         friend class Bob;       // [A] existing syntax
>         friend class Bar =      // [B] proposed syntax
>             x, g(int);
>     };
>
>     class Bob
>     {
>         int     f();    // can access all members of Foo
>     };
>
>     class Bar
>     {
>         int     f();    // can access Foo::x & Foo::g(int) only
>     };
>
> Such a notation (shown at [B]) would allow us to explicity limit
> the members of Foo that the member functions of class Bar can
> access.  (The existing syntax shown at [A] would still mean "export
> all members of Foo to friend class Bar".)
>
> This would plug a hole that exists in the type-safety (data
> hiding) mechanism of C++.

You can easily get this by an intermediate class:

class Foo
{
  friend class Bob;       // [A] existing syntax
  friend class BarAccess; // [B] proposed syntax
private:
  int     x;
  int     y;
  int     g();
  void    g(int i);
};

class BarAccess
{
  friend class Bar;
private:
  int& x(Foo& foo) { return foo.x; }
  void g(Foo& foo, int i) { foo.g(i); }
};

class Bob
{
  void f(Foo&); // can access all members of Foo
};

class Bar
{
  void f(Foo&); // can only access Foo::x and void foo::g(int)
};

void Bar::f(Foo& foo)
{
  BarAccess access;
  cout << "foo.x = " << access.x(foo) << endl;
  access.x(foo)=5;   // foo.x=5;
  access.g(foo, 42); // foo.g(42);
}


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: David R Tribble <dtribble@technologist.com>
Date: 1999/03/20
Raw View
When declaring a friend of a class, it would be nice to be able to
list the members you want the friend (class or function) to be
able to access; any member of the class not in the list could not
be accessed by the friend.

For example, we could use a syntax like that shown at [B]:

    class Foo
    {
    private:
        int     x;
        int     y;
        int     g();
        void    g(int i);

        friend  class Bob;          // [A] existing syntax
        friend  class Bar using     // [B] proposed syntax
                    x, g(int);
        friend  int glob(int i)
                    using x;        // [B] proposed syntax
    };

    class Bob
    {
        int     f();    // can access all members of Foo
    };

    class Bar
    {
        int     f();    // can access Foo::x & Foo::g(int) only
    };

    int glob(int i)
    {
        ...             // can access Foo::x
    }

Such a notation ([B]) would allow us to explicity limit the
members of Foo that the member functions of class Bar can access.
(The existing syntax ([A]) would still mean "export all members of
Foo to friend class Bar".)

This would plug a hole that exists in the type-safety (data hiding)
mechanism of C++.

-- David R. Tribble, dtribble@technologist.com --
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]