Topic: ptr-to-anonymous members, object layout, inheriting C structs


Author: mcg@wheezy.CS.Berkeley.EDU (Michael C. Greenspon)
Date: 1997/06/05
Raw View
Two part question--

1) If I inherit 'data members' from a C struct as the first base of a
derived class with virtual functions, is the pointer to derived still
guaranteed equivalent to a pointer to the base for all implementations?
That is, given:

   struct C {
      int d;
      union {
         struct {
            int x;
         } a;
         struct {
            int y, x;
         } b;
      } u;
   } c;

   struct V {
      virtual v() ;
   };

   struct D : public C, public V {
      virtual d();
   };

   D* dp = new D;

   will  ( dp - (C*) dp == 0 ) always?  Sure hope the answer is still 'yes'.

2) Given the above structure with an anonymous member union of anonymous
structs, I'd like to build a table of 'offsets' or ptr-to-members to unify
access to a nested member 'x' which occurs at varying places in the
structs according to the discriminant 'd'. In other words I'd like to do
something like:

   enum discr { a = 0, b };
   int offsets[] = {
        offset_of( C.u.a, x );
        offset_of( C.u.b, x );
   };

   int x = *(int*) (((void*) dp) + offsets[dp->d]);

Is there a 'better' or type-safe way to do this? I don't see a way to do
it with ptr-to-members--

   int D::* pmd = &D:: ??? // can't take address of unnamed member?!
   int D::* pmd = &D::u.b.x; // nope...?

I thought the latter would work but my compilers won't get past the D::u
before complaining that the non-static member must be associated with an
object or object pointer.

Obviously the base C struct represents legacy code and cannot be altered
(read-only source.) I'd rest with the 'offset_of' table but I recall some
discussion about the implementation dependencies of this going forward
under the draft standard (hence comp.std.c++.) What's the best C++
language approach to this situation (aside from shooting the original C
programmers)?

Email response appreciated.

Thanks,
--Michael
mcg@grok.berkeley.edu
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Paul D. DeRocco" <pderocco@ix.netcom.crud.com>
Date: 1997/06/05
Raw View
Michael C. Greenspon wrote:
>
> 1) If I inherit 'data members' from a C struct as the first base of a
> derived class with virtual functions, is the pointer to derived still
> guaranteed equivalent to a pointer to the base for all implementations?
> That is, given:
>
>    struct C {
>       int d;
>       union {
>          struct {
>             int x;
>          } a;
>          struct {
>             int y, x;
>          } b;
>       } u;
>    } c;
>
>    struct V {
>       virtual v() ;
>    };
>
>    struct D : public C, public V {
>       virtual d();
>    };
>
>    D* dp = new D;
>
>    will  ( dp - (C*) dp == 0 ) always?  Sure hope the answer is still 'yes'.

The answer is yes, only but because the compiler does automatic pointer
conversion whenever you combine two different but related types. If the
question is:

    will ((char*)dp == (char*)(C*)dp) always?

then the answer may well be no. This is because some compilers insist
upon putting vtbl pointers at the beginning of the structure. In this
case, a D will look like:

 A vtbl pointer for class D
 the data for base class C
 A vtbl pointer for base class V
 the data for base class V

--

Ciao,
Paul

(Please remove the extra "crud" from the return address,
which has been altered to foil junk mail senders.)
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/06/05
Raw View
[ Followups set to comp.std.c++ ]

Michael C. Greenspon <mcg@wheezy.CS.Berkeley.EDU> writes:

> Two part question--
>
> 1) If I inherit 'data members' from a C struct as the first base of a
                                                        ^^^^^
                                                     irrelevant

> derived class with virtual functions, is the pointer to derived still
> guaranteed equivalent to a pointer to the base for all implementations?
> That is, given:

[ sniped - definition of base classes: irrelevant ]

>    struct D : C

[ sniped ]

>    {
>       virtual d();
>    };
>
>    D* dp = new D;
>
>    will  ( dp - (C*) dp == 0 ) always?  Sure hope the answer is still 'yes'.

The answer to your _problem_ is no; you are always relying on
common practice.

BTW the answer to the question 'dp - (C*) dp == 0' is always true
(by definition dp == (C*) dp for _any_ base class C) but I'm sure
that you aren't interrested in that.

The real question is of course:
         convert<void*> (dp) == convert <C*> (dp)
which isn't garantied at all.

[ annother question ]

>    enum discr { a = 0, b };

By definition, a == 0 is true.

>    int offsets[] = {
>         offset_of( C.u.a, x );
>         offset_of( C.u.b, x );
>    };
>
>    int x = *(int*) (((void*) dp) + offsets[dp->d]);

Ptr arithmetic isn't defined on void*.

--

Valentin Bonnard
mailto:bonnardv@pratique.fr
http://www.pratique.fr/~bonnardv (Informations sur le C++ en Francais)
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]