Title
Casting across protected inheritance
Status
drafting
Section
11.8.5 [class.protected]
Submitter
Mike Miller

Created on 2004-06-16.00:00:00 last changed 153 months ago

Messages

Date: 2011-04-15.00:00:00

Proposed resolution (April, 2011)

Change 11.8.3 [class.access.base] paragraph 4 as follows:

A base class B of N is accessible at R, if

  • an invented public member of B would be a public member of N, or

  • R occurs in a member or friend of class N, and an invented public member of B would be a private or protected member of N, or

  • R occurs in a member or friend of a class P derived from N, and an invented public member of B would be a private or (but not a protected [Footnote: A protected invented member is disallowed here for the same reason the additional check of 11.8.5 [class.protected] is applied to member access: it would allow casting a pointer to a derived class to a protected base class that might be a subobject of an object of a class that is different from the class context in which the reference occurs. —end footnote]) member of P, or

  • there exists a class S such that B is a base class of S accessible at R and S is a base class of N accessible at R.

[Example:

    class B {
    public:
      int m;
    };

    class S: private B {
      friend class N;
    };
    class N: private S {
      void f() {
        B* p = this;    // OK because class S satisfies the fourth condition
                        // above: B is a base class of N accessible in f() because
                        // B is an accessible base class of S and S is an accessible
                        // base class of N.
      }
    };

    class N2: protected B { };

    class P2: public N2 {
      void f2(N2* n2p) {
        B* bp = n2p;    // error: invented member would be protected and naming
                        // class N2 not the same as or derived from the referencing
                        // class P2
        n2p->m = 0;     // error (cf 11.8.5 [class.protected]) for the same reason
      }
    };

end example]

Date: 2004-10-15.00:00:00

Notes from October 2004 meeting:

The CWG tentatively agreed that casting across protective inheritance should be subject to the additional restriction in 11.8.5 [class.protected].

Date: 2004-06-16.00:00:00

Does the restriction in 11.8.5 [class.protected] apply to upcasts across protected inheritance, too? For instance,

    struct B {
        int i;
    };
    struct I: protected B { };
    struct D: I {
        void f(I* ip) {
            B* bp = ip;    // well-formed?
            bp->i = 5;     // aka "ip->i = 5;"
        }
    };

I think the rationale for the 11.8.5 [class.protected] restriction applies equally well here — you don't know whether ip points to a D object or not, so D::f can't be trusted to treat the protected B subobject consistently with the policies of its actual complete object type.

The current treatment of “accessible base class” in 11.8.3 [class.access.base] paragraph 4 clearly makes the conversion from I* to B* well-formed. I think that's wrong and needs to be fixed. The rationale for the accessibility of a base class is whether “an invented public member” of the base would be accessible at the point of reference, although we obscured that a bit in the reformulation; it seems to me that the invented member ought to be considered a non-static member for this purpose and thus subject to 11.8.5 [class.protected].

(See also issues 385 and 471.).
History
Date User Action Args
2011-09-06 00:00:00adminsetstatus: review -> drafting
2011-04-10 00:00:00adminsetstatus: drafting -> review
2010-08-23 00:00:00adminsetstatus: review -> drafting
2010-02-16 00:00:00adminsetmessages: + msg2549
2010-02-16 00:00:00adminsetstatus: drafting -> review
2005-10-22 00:00:00adminsetstatus: open -> drafting
2004-11-07 00:00:00adminsetmessages: + msg1088
2004-06-16 00:00:00admincreate