[comp.lang.c++] Access to protected members

masotti@usc.edu (Glauco Masotti) (07/18/89)

I had some problems using protected members. I was pretty confident, after
reading the "evolution paper" from Bjarne, that my files would compile, but I
received instead complains from the compiler.  I am using g++, 1.35.0+, so I
first thought of a bug in the compiler and I wrote to the FSF. I kept
exchanging mail with Doug Lea. He told me I should be right, and that he also
would like protected to work the way I used them, but that this doesn't
conform to AT&T 2.0 specs. The interpretation of the evolution paper seems
therefore to be cumbersome, but he also told me to have discussed the matter
with Bjarne himself, to be sure of his interpretation.
 
The following is the example:

---------------------------------------

#include <stream.h>

struct A {

	A(int i) {j=i;}
	void increment() {j++;}
	print() {cout<<j<<"\n";}

protected:
	int j;
};

struct B : A {

	int k;
	A* a;
	B(int i, int j, A* x) : A(i) {k=j; a=x;}
	print() {cout<<j<<" "<<k<<" "<<a->j"\n";}
};


main()
{
	int i=9;

	A a(i);
	a.increment();
	a.print();

	B b(2, 3, &a);
	b.print();
}

------------------------------------------------

Here a protected member of a class is accessed through a pointer in a member
function of a derived class. 
To me this should be allowed, I find pretty counterintuitive the contrary. 
I would like to know what people think.  If Andrew or Bjarne are listening I
would appreciate very much their response.

In any case if I cannot write something like the previous example, I think the
cases where the protection mechanism will help instead of being a burden will
shrink significantly. Therefore the problems protected was intended to solve (as
reported in the evolution paper) will not be solved and we will be forced to
resort again to public everything or make a lot of friends (which in C++ is
not as good as in life :-)).

-Glauco Masotti

masotti@lipari.usc.edu


P.S. This is my first posting, so... Hello to everybody! You may here from me
again if I keep working on my current project.

ark@alice.UUCP (Andrew Koenig) (07/18/89)

In article <MASOTTI.89Jul17110844@lipari.usc.edu>, masotti@usc.edu (Glauco Masotti) writes:

> I had some problems using protected members. I was pretty confident, after
> reading the "evolution paper" from Bjarne, that my files would compile, but I
> received instead complains from the compiler.

Rather than jumping into your example right away, let's look
at a simpler one.

	class X {
	protected:
		int x;
	};

The idea of `protected' is to nominate parts of a class that may
only be used as scaffolding on which to build derived classes.
Thus, for example, the following is legal:

	class Y: public X {
	public:
		void zot() { x = 0; }
	};

because, although Y::zot() appears to be clobbering X::x,
in fact it does so only in its capacity as a part of a Y.
For instance, suppose we change the definition of Y:

	class Y: public X {
	public:
		void zot() { x = 0; }
		void clear(X& xr) { xr.x = 0; }
	};

We then get a message that Y::clear() cannot access X::x,
because xr.x is a member of a plain old X, not an X that's
known to be part of a Y.

Although this treatment seems counterintuitive at first, there
are several reasons for it.

First, if C++ did not restrict things this way, anyone could
circumvent protection for any protected member of any object
merely by deriving a dummy class as shown above.

Second, it is quite easy to make things less restrictive if
that's what you want: in this example, for instance, you could
make Y a friend of X or make X::x public.  It is much harder
to make things more restrictive.


Most of us who have grappled with this problem have found that
there's often a way of doing what we want without running afoul of
the protection restrictions.  The solution, once found, may
well be cleaner than the original version.  Try it and see.
-- 
				--Andrew Koenig
				  ark@europa.att.com

sakkinen@tukki.jyu.fi (Markku Sakkinen) (07/21/89)

In article <MASOTTI.89Jul17110844@lipari.usc.edu> masotti@usc.edu (Glauco Masotti) writes:
>I had some problems using protected members. I was pretty confident, after
>reading the "evolution paper" from Bjarne, that my files would compile, but I
>received instead complains from the compiler.  I am using g++, 1.35.0+ ...
> ...
>The following is the example:
> ...
>
>Here a protected member of a class is accessed through a pointer in a member
>function of a derived class. 
>To me this should be allowed, I find pretty counterintuitive the contrary. 
>I would like to know what people think.  If Andrew or Bjarne are listening I
>would appreciate very much their response.

The essence of Masotti's example compiled all right under release 1.2
(Glockenspiel's Designer C++); I just had to edit a couple of other details.
However, checking in Stroustrup's "evolution paper" from the USENIX
C++ Workshop 1987, I found a rather clear statement to the contrary on p. 3:
 "A member or a friend of a derived class has access only to protected members
  of objects that are known to be of its derived type."

(***) (see below)
>In any case if I cannot write something like the previous example, I think the
>cases where the protection mechanism will help instead of being a burden will
>shrink significantly. Therefore the problems protected was intended to solve (as
>reported in the evolution paper) will not be solved and we will be forced to
>resort again to public everything or make a lot of friends (which in C++ is
>not as good as in life :-)).
>
>-Glauco Masotti
>
>masotti@lipari.usc.edu

In article <9630@alice.UUCP> ark@alice.UUCP (Andrew Koenig) writes:
> ...
>The idea of `protected' is to nominate parts of a class that may
>only be used as scaffolding on which to build derived classes.
> ...
>
>Although this treatment seems counterintuitive at first, there
>are several reasons for it.
>
>First, if C++ did not restrict things this way, anyone could
>circumvent protection for any protected member of any object
>merely by deriving a dummy class as shown above.

This argument is valid, but not yet overwhelming:
there are so many means to circumvent all kinds of protection
in C++ anyway.

>Second, it is quite easy to make things less restrictive if
>that's what you want: in this example, for instance, you could
>make Y a friend of X or make X::x public.  It is much harder
>to make things more restrictive.

This suggestion is exactly what Masotti protested against under (***)!

>Most of us who have grappled with this problem have found that
>there's often a way of doing what we want without running afoul of
>the protection restrictions.  The solution, once found, may
>well be cleaner than the original version.  Try it and see.

This sounds like the Oracle of Delfoi (Delphi) - leaves me puzzled.
If it means e.g. that one should sometimes add more public functions
to the base class than have originally been defined, to allow the
orderly handling of some private or protected variables, I can agree.

>-- 
>				--Andrew Koenig
>				  ark@europa.att.com

There are more reasons than (***) why it could be recommendable to allow
a member or friend function of a derived class to access protected
"members" (I do dislike the meaning given to the word 'member' in
C++ literature) of base class objects:

1. Encapsulation in C++ is otherwise on the level of _classes_,
   as opposed to Smalltalk (every object encapsulated from all others)
   and Simula (no encapsulation); this would be more analogous.

2. The rules for protected parts would be a little simpler.

3. It would be compatible with earlier versions of C++ (as noted in
   the beginning of this posting).

However, interpreting 'protected' like this would logically require
that one could declare something similar to friend classes and functions,
i.e. access rights to protected members for some others beside
derived classes. Perhaps 'cousin' would do - although I have claimed
to oppose to anthropomorphic terminology. See the suggestion for
'acquaintance' in my paper in SIGPLAN Notices, December 1988.

Markku Sakkinen
Department of Computer Science
University of Jyvaskyla (a's with umlauts)
Seminaarinkatu 15
SF-40100 Jyvaskyla (umlauts again)
Finland

richard@pantor.UUCP (Richard Sargent) (03/20/90)

(I apologize if this has been seen before, but I have had no
indication that it successfully made its way out into the world.)

We have encountered a problem with C++ 2.0, and diligent reading
of the manual confirms that we are wrong. :-(

I am left with a couple of questions as a result, but first the
problem:

We have a tree of classes, such as various graphics objects. We
want to have some base class members be accessible only to objects
from this tree of classes. No problem you say, just use protected.
There's the nub: any given object can access its protected base
members, but not those of any other object derived from the same
tree. (Reference: AT&T Reference Manual, Select Code 307-146, 
section 11.5 Protected Member Access, page 73)

For example, we have a derived class which we want to be able to
traverse an array of graphics objects (of which class it is, too).
However, this object (and its member functions) cannot access the
protected members of the objects in this array.

Q1: Why was the language specified with this restriction? I am not
a language designer, so I don't understand the decisions that might
be obvious to some one is. I certainly don't presume to think that
Stroustrup is incorrect, but I do want to understand the ratioanle
here.

Q2: Given that this restriction is part of the language, how can I
work around it? The obvious solution is to make the member in question
"public", but then everything has access to it. However, I see
no alternatives.

Any and all help and explanations welcomed and appreciated.
Thanks in advance.

Richard Sargent                   Internet: richard@pantor.UUCP
Systems Analyst                   UUCP:     ...!mnetor!becker!pantor!richard