[comp.lang.c++] protected members

lindsay@stobhill.newcastle.ac.uk (Lindsay F. Marshall) (11/28/89)

I have an application that worked under the 1.2 rules but wil not
compile under 2.0. This seems to be to a considerable tightening of
the rules for protected members. What I am not sure is whether or not
it is correct!! The situation

	class A
	{
	protected::
		A();
		~A();
		void* data;
	};

	class B : public A
	{
	public:
		B();
		~B();
		A* next;
	};

So B is derived from and A and an instance of class B can access the
field data without problems. However, if the class B uses an instance
of class A inside one of its members, for example:


	B::~B()
	{
		while (next != this)
		{
			delete next;
		}
	}

The compiler will not permit this access saying that the destructor is
protected. The same thing happens if one tries to access next->data.
Is this correct or is the compiler being too strict? If it's correct
is there any point in having a protected, non-virtual destructor - it
might as well be private.

This happens with both C++ 2.0 and g++ 1.36.1 .

Lindsay
--
MAIL : Lindsay.Marshall@newcastle.ac.uk (UUCP: s/\(.*\)/...!ukc!\1/)
POST : Computing Laboratory, The University, Newcastle upon Tyne, UK NE1 7RU
VOICE: +44-91-222-8267 		FAX: +44-91-222-8232

peter@mit-amt.MEDIA.MIT.EDU (Peter Schroeder) (11/29/89)

In article lindsay@stobhill.newcastle.ac.uk (Lindsay F. Marshall) writes:

	class A
	{
	protected::
		A();
		~A();
		void* data;
	};

	class B : public A
	{
	public:
		B();
		~B();
		A* next;
	};

	B::~B()
	{
		while (next != this)
		{
			delete next;
		}
	}

>The compiler will not permit this access saying that the destructor is
>protected. The same thing happens if one tries to access next->data.
>Is this correct or is the compiler being too strict?

This is correct. As a member of B, A* is just some class and can only be
accessed as allowed by the original class definition.

If we defined a class D which looks exactly like class A and then replaced
the occurence of A* in B by D* it would be clear that we cannot expect to
be able to access D's desctructor.

I stumbled over this a few times, since 1.2.1 of cfront did not seem to
enforce it, but I can now see that it makes sense to forbid this.

Hope this helps.

Peter
peter@media-lab.media.mit.edu

sakkinen@tukki.jyu.fi (Markku Sakkinen) (11/30/89)

In article lindsay@stobhill.newcastle.ac.uk (Lindsay F. Marshall) writes:
-I have an application that worked under the 1.2 rules but wil not
-compile under 2.0. This seems to be to a considerable tightening of
-the rules for protected members. What I am not sure is whether or not
-it is correct!! The situation
-
-	class A
-	{
-	protected::
-		A();
-		~A();
-		void* data;
-	};
-
-	class B : public A
-	{
-	public:
-		B();
-		~B();
-		A* next;
-	};
-
-So B is derived from and A and an instance of class B can access the
-field data without problems. However, if the class B uses an instance
-of class A inside one of its members, for example:
-
-
-	B::~B()
-	{
-		while (next != this)
-		{
-			delete next;
-		}
-	}
-
-The compiler will not permit this access saying that the destructor is
-protected. The same thing happens if one tries to access next->data.
-Is this correct or is the compiler being too strict? If it's correct
-is there any point in having a protected, non-virtual destructor - it
-might as well be private.
-
-This happens with both C++ 2.0 and g++ 1.36.1 .

In article <1111@mit-amt.MEDIA.MIT.EDU> peter@media-lab.media.mit.edu (Peter Schroeder) writes:
>[...]
>This is correct. As a member of B, A* is just some class and can only be
>accessed as allowed by the original class definition.
>
>If we defined a class D which looks exactly like class A and then replaced
>the occurence of A* in B by D* it would be clear that we cannot expect to
>be able to access D's desctructor.
>
>I stumbled over this a few times, since 1.2.1 of cfront did not seem to
>enforce it, but I can now see that it makes sense to forbid this.
>
>Hope this helps.

This problem was discussed here some 2 months (?) ago.
I and someone else argued that the old principle is logical
insofar as the unit of encapsulation in C++ is a class
(and not an object as in Smalltalk, say).
Of course there are arguments in favour of the new principle, too.
However, with regard to the much-advertised "stability" of C++
the _change_ was unfortunate.
This restriction is explicitly written in section 11.5 of the
new C++ Reference Manual (thank you, Bjarne, for sending me a copy).

To solve the problem in the original question, it seems necessary
to declare B also a friend of A. This means that the definition
of A must be changed when such derived classes are added,
which may not always be convenient. One possible trick to circumvent
this comes to mind, but I cannot deduce from the Ref.Man. whether
it is legal in current C++:
Define a dummy class AA and declare it a friend class of A.
Then, since we now have multiple inheritance, make AA another
public base class of B.
If classes derived from a friend class of A remain friends of A,
this should work, otherwise not.

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

sakkinen@tukki.jyu.fi (Markku Sakkinen) (11/30/89)

Sorry, I posted the previous article without thinking about this:
_If_ the trick suggested at the end (deriving from a dummy friend class)
works, then of course B gains access to private members of A as well.
This is an unwanted consequence. Perhaps a "half-friend" declaration
should be added to C++, allowing access to protected but not to private
members ('acquaintance' has been pre-empted for other purposes :-) ).

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

jaa@hutcs.hut.fi (Jari Alasuvanto) (06/21/90)

We ran into the following problems when switching from 1.2 (Glockenspiel) to
2.0 (Sun).
Let's make a simple example:
class first {
        int val2 ;
protected:
        void foo() ;
} ;

class second : public first {
        int val ;
} ;

class third : public first {

        void bar(second& ref) ;
} ;

void first::foo()
{}

void third::bar(second& ref)
{ ref.foo() ;}

produces an error message on sparc, Sun's 2.00 CC
"tmp.cxx", line 22: error:  third::bar() cannot access first::foo(): protected  member
1 error
but passes OK with Glockenspiel 1.2 on sun3. 

The question is:
Is this a new (redefined) feature of 2.0 or does one of the compilers have
a bug in handling this kind of code ?

Thanks in advance, sorry if this has been asked earlier in this group.

	Jari Alasuvanto
--
Jari Alasuvanto	
Lab. of Information Proc. Science, Helsinki Univ. of Techology, Finland
Internet: 	jaa@hutcs.hut.fi 	Bitnet:	jaa%finhutcs.bitnet	
tel: 		+358-0-451 3236 	fax:  +358-0-465 077