From -7906586240564423994
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: f78e5,d7194cd08c8b2eab
X-Google-Attributes: gidf78e5,public
From: JdeBP@jba.co.uk (Jonathan de Boyne Pollard)
Subject: Re: Access control
Date: 1995/07/08
Message-ID: <3tm49o$qdu@silver.jba.co.uk>
X-Deja-AN: 105843533
references: <3te3a8$9cp@silver.jba.co.uk> <3tlnmd$1es@crcnis3.unl.edu>
organization: JBA Software Products, Studley, England.
reply-to: JdeBP%utopium@jba.co.uk
newsgroups: comp.std.c++

Eric Biederman (ebiederm@cse.unl.edu) wrote:
: JdeBP@jba.co.uk (Jonathan de Boyne Pollard) writes:
: >//
: >//	The following code does not compile on MetaWare High C++ 3.31a,
: >//	but compiles without error on Borland C++ 2.0 for OS/2, IBM 
: >//	VisualAge C++ 3.00, EMX C++ 0.9a, and Watcom C++ 10.0b.  
: >//
: >
: >struct Base {
: >	void g() ;
: >protected:
: >	void f() {}
: >} ;
: >
: >struct Derived: public Base { } ;
: >
: >void
: >Base::g ()
: >{
: >	Derived d ;
: >	d.f() ;
: >}
:
: By reading Section 11 of the ARM here is what I come up with.

I was reading chapter 11 of the working paper.  It's slightly different to
the ARM.  You'll note, specifically, that 11.2 has changed.  Whereas the
ARM says

: 11.2
: If a class is declared to be a base class for another class using the public
: access specifier, the public members of the base class are public members
: of the derived class and protected members of the base class are protected
: members of the derived class.  ...

the working paper says

: 11.2
: If a class is declared to be a base class for another class (_class.derived_)
: using the public access specifier, the public members of the base class are 
: accessible as public members of the derived class and protected members of 
: the base class are accessible as protected members of the derived class.  ...

which is not (to my mind) a gratuitous change.  There must be some intent
here, and it seems that the intent is to clear up the confusion about
membership.  It seems that inheritance doesn't cause actual transference of 
membership from base to derived, but instead allows access to base members
as if they were members of derived (i.e. using the same syntax).

: >//	By my reading of Chapter 11 of the WP, MetaWare is right and the
: >//	others wrong.  The only way to achieve the desired result should be
: >//	to cast `d' to `Base &' before attempting the member access.
: >//
: >//	Comments please.

: Please comment on my comments and show me where you disagree.

All right.  Here goes.

: The question then remains are a, b [in the example in Chapter 10 of the
: ARM] also members of base while simultaneously being members of the derived.
: I would say that they are.
:
: If this is the case then the quotes that are present should be enough to
: say the the error message is _wrong_ and that f is accessible as it is
: a base class member. Being called from the base class.

I disagree partly because members are only members of the class they are
declared in, and membership is not transferred, and partly because of the 
wording in the working paper :

11.5 Protected Member Access                      [class.protected]

2 A friend or a member function of a derived class can access a protected
  nonstatic member of a base class.  Except when forming a pointer to
  member (_expr.unary.op_), the access must be through a pointer to,
  reference to, or object of the derived class itself (or any class derived
  from that class) (_expr.ref_).  [...]

Which is very similar to the verse from the ARM that you quoted.

In my original example, the object *is* an object of the derived class, so
the second part of the verse is satisfied.  Unfortunately, the first
part is *not* satisfied, since the function that is attempting the access
is *not* a friend or member of the derived class.  It is a member of the
*base* class.

In other words, it seems to be the intention that whilst the implicit
Derived->Base conversion on `this' allows access to protected members of
Base in members of Derived, there is *no* implicit Derived->Base
conversion on instances of Derived when we are not in the class scope of
Derived.

Another argument for agreeing with the minority of C++ compilers is that if
Base::g() were a non-member function, we would expect the error message as
a matter of course, since non-member functions have only public access to
members of Derived and to public members of its public base classes, which
category clearly does not include Base::f(), it being a protected member.

I think that [class.protected] is very clear on protected access, and
(rightly or wrongly) restricts it specifically to access to protected 
members of base classes when in the class scope of derived classes.

This seems pretty clear cut to me, and what amazed me initially was that my
first reaction (when I first encountered this) that "the majority is right" 
was, in fact, wrong upon close reading of the language specification.

About the only quibble that I can see is the one that you brought up at the
end of your message, which is that the instance of Derived may be implicitly
converted to a reference to Base, allowing the function member of Base to
access the protected member of that instance.  I agreed in my original
message that if the conversion was *explicit* then this was all right (and
this is the "workaround" for the problem, of course), but I cannot find
anything to justify an *implicit* conversion.

The verse in Chapter 10 of the ARM that you quoted in support of an implicit
reference conversion has actually been tightened up in the working paper,
and now only talks about binding an lvalue of Derived to a reference to
Base, rather than implicit reference conversions from the one to the
other.

So although I'm grateful for your taking the time to argue this out with
me and I'm still open to being persuaded on the subject, you haven't yet 
convinced me that the minority of C++ compilers (Hewlett-Packard and
MetaWare) is wrong and the majority (IBM, Borland, EMX, and Watcom) right on 
this issue yet.



