Topic: pointer to member conversion
Author: dak <pierreba@poster.cae.ca>
Date: 1996/05/09 Raw View
Fergus Henderson (fjh@mundook.cs.mu.OZ.AU) wrote:
> ball@eng.sun.com (Mike Ball) writes:
[snipped description of problem]
> >It's safe, but it's expensive if virtual bases are involved in any way,
> >since you need an actual instance of the class to do the cast.
[snip]
> I guess it would be possible to allow the conversions only for non-virtual
> base classes, but that would probably be too tricky -- it's better to
> disallow them all.
I'm not sure I agree with that (so what? :). There are already things
prohibited when it involves virtual base classes, like down-casting
(provided there is no virtual functions). The prohibition on pointer-
to-member conversion involving virtual base is very easy to state, simply
disallow them. Note also that g++ currently support such casting, so it's
not a complexity of implementation issue. And it does simplify things when
needed: under g++, I was able to implement relation classes with one base
class and derivatives. The code is clear. Without pointer-to-member
conversion, I have to write a parallel hierarchy of "inverse" pointer which
hides the conversion until after the pointer-to-member to the desired class
is dereferenced. The code is NOT the least self-explanatory.
Oh well. At least there's a work-around this one.
Pierre "ALL temp are const? oh no!" Baillargeon
---
[ 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: JdeBP@jba.co.uk (Jonathan de Boyne Pollard)
Date: 1996/04/26 Raw View
Vladimir Neyman (Vladimir_Neyman@stratus.com) wrote:
| class A {};
|
| class B : public A {};
|
| struct C {
| B m_b;
| }
|
| A C::*p = &C::m_b;
|
| The last assignement produces a compiler error in MVC:
| "cannot convert from 'class B C::*' to 'class A C::*'".
|
| At first, I thought it is a bug in MVC because a pointer to
| a derived class should be convertable to a pointer to a
| base class.
|
| But then I looked into standard draft and found ($4.11) that for
| pointers to members, onthe opposite, a pointer to a base class is
| convertable to a pointer to a derived class. The standard says that
| this inversion of normal rules is necessary for type safety.
What the standard is actually says is that "an rvalue of type pointer to
member of B of type cv T, where B is a class type, can be converted to an
rvalue of type pointer to member of D of type cv T, where D is a derived
class of B".
Substituting for your example, "a pointer to member of `C' of type A"
is convertible to "a pointer to member of `D' of type A", assuming a class
D derived from C (which is not in your example).
The rationale of allowing "Base::*" to be converted to "Derived::*" is, of
course, that all of the members of "Base" are also members of "Derived", so
the conversion is safe, whereas the converse is not true.
What you are trying to do, however, is convert from "a pointer to member
of `C' of type B" to "a pointer to member of `C' of type A". In my
slightly out of date copy of the WP (Steve Rumsby where are you?), at
least, there is *no* pointer-to-member conversion that allows that.
I would guess that the reasoning behind this is that pointers to members
are *not* pointers to objects. Whereas "B *" is a pointer to an object
and can be converted to "A *", a "B C::*" is a pointer to a *member*, and
you need to supply an object of type `C' before you can get an object of
type `B' out of it, let alone a "B *". For example :
B C::* ptr_m_b = &C::m_b ; // pointer to member of class C, type B
C c ; // object of class C
A * ptr_a = &c.*ptr_m_b ; // Convert "B *" to "A *"
I'm as surprised as you are that Microsoft C++ appears to have got it right
for once.
[ 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: Vladimir Neyman <Vladimir_Neyman@stratus.com>
Date: 1996/04/26 Raw View
I have the following code (details not essential to the problem are
omitted):
class A {};
class B : public A {};
struct C {
B m_b;
}
A C::*p = &C::m_b;
The last assignement produces a compiler error in MVC:
"cannot convert from 'class B C::*' to 'class A C::*'".
At first, I thought it is a bug in MVC because a pointer to
a derived class should be convertable to a pointer to a
base class.
But then I looked into standard draft and found ($4.11) that for
pointers to members, onthe opposite, a pointer to a base class is
convertable to a pointer to a derived class. The standard says that
this inversion of normal rules is necessary for type safety.
Does anybody know why this inversion is necessary for type safety?
Is it safe to do explicit typecast from 'class B C::*' to 'class A
C::*' in the above example?
Regards,
Vladimir Neyman
[ 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: Martin D Kealey <martin@kcbbs.gen.nz>
Date: 1996/04/29 Raw View
In article <3180E8D7.4352@stratus.com>
Vladimir_Neyman@stratus.com <Vladimir Neyman> wrote:
> I have the following code (details not essential to the problem are
> omitted):
> class A {};
> class B : public A {};
> struct C {
> B m_b;
> }
> A C::*p = &C::m_b;
> The last assignement produces a compiler error in MVC:
> "cannot convert from 'class B C::*' to 'class A C::*'".
> I looked into standard draft and found ($4.11) that for
> pointers to members, on the opposite, a pointer to a base class is
> convertable to a pointer to a derived class. The standard says that
> this inversion of normal rules is necessary for type safety.
I don't have a copy of the standard to check the exact wording myself,
but if it fails to make clear the distinction between pointer INTO a
class vs pointer TO a class, then I believe a defect report would be in
order.
> Does anybody know why this inversion is necessary for type safety?
> Is it safe to do explicit typecast from 'class B C::*' to 'class A
> C::*' in the above example?
Sounds like they got the wording a little bit wrong there; the
inversion of the conversion applies only to pointers INTO a
class, not pointers TO one.
Given classes
class A {
int mA;
};
typedef int A::*PMA;
class B : public A {
int mB;
};
typedef int B:*PMB;
then this is not allowed:
PMB pmb = &B::mB;
PMA pma = pmb; // not allowed
A a;
a.*pma = 1; // just as well, since this member doesn't exist.
but this should work:
PMA pma = &A::mA;
PMB pmb = pma; // ok
B b;
b.*pmb = 1; // member in base class
- Martin.
---
[ 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: JdeBP@jba.co.uk (Jonathan de Boyne Pollard)
Date: 1996/05/02 Raw View
Mike Ball (ball@eng.sun.com) wrote:
| In article 5d3@mulga.cs.mu.OZ.AU, fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
| writes:
| >
| > We're talking about members of `C', not members of `Derived' or `Base'.
| > In words, conversion from `Derived C::*' to `Base C::*' is converting
| > from a pointer to a member of class `C' whose type is `Derived',
| > to a pointer to a member of class `C' whose type is `Base'.
| > Why is this unsafe?
|
| It's safe, but it's expensive if virtual bases are involved in any way,
| since you need an actual instance of the class to do the cast. This
| means that you have to save up all of the casts then do them after you
| have dereferenced the pointer to member itself. When we discussed this
| in the working group we decided that the amount of mechanism was
| probably unjustified for such a small gain in generality.
To save other non-XJ16 readers of comp.std.c++ the headache, I think that I
have successfully reverse engineered what Mike is talking about. Consider
three classes ...
class VirtualBase {} ;
class Derived : public virtual VirtualBase {} ;
class FurtherDerived : public Derived, publiv virtual VirtualBase {} ;
When the compiler encounters the the second pointer conversion in
Derived * ptr_to_d = new FurtherDerived ;
Base * ptr_to_b = ptr_to_d ;
it has to generate code that goes into the Derived (sub-)object pointed to
by `ptr_to_d' and picks out its virtual base pointer. This is because the
position of the VirtualBase sub-object within a complete object of Derived
might be different to the position of the VirtualBase sub-object relative
to the Derived sub-object within a complete object of FurtherDerived.
A simple pointer offset calculation (as would be performed in the case of
non-virtual bases) is insufficient.
When it comes to pointers to members, the same situation occurs. Assume
that we introduce a standard conversion between `Derived C::*' and `Base
C::*'. In
class C {
Derived d ;
FurtherDerived f ;
} ;
Derived C::* ptr_to_member_d_of_type_d = &C::d ;
Derived C::* ptr_to_member_f_of_type_d = &C::f ;
Base C::* ptr_to_member_d_of_type_b = ptr_to_member_d_of_type_d ;
Base C::* ptr_to_member_f_of_type_b = ptr_to_member_f_of_type_d ;
at run-time, again, the complete object for the `Derived C::*' data member
would be needed in order to compute the new offset for the `Base C::*',
since a statically-computed offset calculation would not work for virtual
base classes.
In the case of pointers to objects, we know that ptr_to_d either points to
an object or is a NULL pointer, so at runtime the code can either just
convert to the destination NULL pointer or perform the vbase-pointer lookup,
which satisfies the requirements of the standard [conv.ptr 3].
Unfortunately, in the case of pointers to members, we do not *have* an
object to play with (pointers to members are not pointers to objects), so
there's no way that the vbase-pointer lookup can be performed at runtime at
the time of the pointer conversion.
As Mike vaguely indicated, it would be possible to save up all of the
conversions applied in the internals of the pointer-to-member, and then
apply them when the pointer-to-member was finally applied to an object of
class C.
For example, taking the above, `ptr_to_member_d_of_type_b' would have
the same offset as `ptr_to_member_d_of_type_d' (since a new offset
could not be calculated at the time that the conversion took place),
but would also extra information saying that a conversion from
`Derived' to `Base' needs to be applied. Then, when it came to
applying the .* operator to an object of class C,
C c_object ;
Base * ptr_to_b_part_of_d = &c_object.*ptr_to_member_d_of_type_b ;
Base * ptr_to_b_part_of_f = &c_object.*ptr_to_member_f_of_type_b ;
the .* operator would use the offset to find the data member object `d' or
'f', and then apply the conversion `Derived &' to `Base &' on that object
to get the final result.
Compare and contrast this with
Base * ptr_to_b_part_of_d = &c_object.*ptr_to_member_d_of_type_d ;
where the .* operator uses the offset to find the data member object `d',
but the conversion `Derived *' to `Base *' is performed on the return from
the & operator.
The complexity of this scheme appears to be a very persuasive argument
against making the conversion from `Derived C::*' to `Base C::*' a
standard conversion.
---
[ 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: jpotter@falcon.lhup.edu (John E. Potter)
Date: 1996/05/04 Raw View
Martin D Kealey (martin@kcbbs.gen.nz) wrote:
: In article <3180E8D7.4352@stratus.com>
: Vladimir_Neyman@stratus.com <Vladimir Neyman> wrote:
: > I have the following code (details not essential to the problem are
: > omitted):
: > class A {};
: > class B : public A {};
: > struct C {
: > B m_b;
: > }
: > A C::*p = &C::m_b;
: > The last assignement produces a compiler error in MVC:
: > "cannot convert from 'class B C::*' to 'class A C::*'".
The discussion seems to be about apples and oranges. Perhaps another
apple may bring consensus on the original question.
struct A {
int a;
};
struct B : A {
int b;
};
struct C {
B c;
};
B gb;
A * pga = &gb; // ok
A C::* pc = &C::c; // ok (cfront, g++); error (MVC, xlC); ?(DWP)
int A::* pa = &B::b; // contravariance violation
John
---
[ 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: "john (j.d.) hickin" <hickin@bnr.ca>
Date: 1996/05/06 Raw View
Change it to:
struct B : public virtual A {
int b;
};
And now you will get:
cfront: core dump
gcc 2.7.2: random value
I am thinking to cast my vote for MVC.
--
John Hickin Nortel Technology, Montreal, Quebec
(514) 765-7924 hickin@nortel.ca
---
[ 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: dak <pierreba@poster.cae.ca>
Date: 1996/04/29 Raw View
JdeBP@jba.co.uk (Jonathan de Boyne Pollard) wrote:
>
> Vladimir Neyman (Vladimir_Neyman@stratus.com) wrote:
> | class A {};
> |
> | class B : public A {};
> |
> | struct C {
> | B m_b;
> | }
> |
> | A C::*p = &C::m_b;
> |
> | The last assignement produces a compiler error in MVC:
> | "cannot convert from 'class B C::*' to 'class A C::*'".
>
[snip]
> What you are trying to do, however, is convert from "a pointer to member
> of `C' of type B" to "a pointer to member of `C' of type A". In my
> slightly out of date copy of the WP (Steve Rumsby where are you?), at
> least, there is *no* pointer-to-member conversion that allows that.
>
> I would guess that the reasoning behind this is that pointers to members
> are *not* pointers to objects. Whereas "B *" is a pointer to an object
> and can be converted to "A *", a "B C::*" is a pointer to a *member*, and
> you need to supply an object of type `C' before you can get an object of
> type `B' out of it, let alone a "B *". For example :
>
The problem of not allowing conversion stems from having abstract base
classes providing interfaces to concrete classes and needing to have a
pointer to member of another class containing such a derived class.
Or in clear, hiding the implementation of class C, in the above example.
For example (don't look at syntax too much, I'm typing this in from the
top of my head):
template <class FROM, class TO> class Relation
{
// abstract relationship class.
};
template <class FROM, class TO> class One_to_X : public Relation<FROM,TO>
{
// concrete one-to-x side.
private:
// we don't know (and don't care) about the other side:
// relations are updated correctly whatever happens.
TO::Relation * mpInverse;
};
template <class FROM, class TO> class Many_to_X : public Relation
{
// another concrete: may to x side.
private:
// we don't know (and don't care) about the other side:
// relations are updated correctly whatever happens.
TO::Relation * mpInverse;
};
Note that you may think that knowing the other side of a relation is
important, and it is, at a USER level, not at the mechanical level.
The benefit of leaving the implementation of the relationship hidden
become obvious once you start having relations between classes that
are abstract themselves.
[ 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: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1996/04/29 Raw View
JdeBP@jba.co.uk (Jonathan de Boyne Pollard) writes:
| Vladimir Neyman (Vladimir_Neyman@stratus.com) wrote:
| | class A {};
| |
| | class B : public A {};
| |
| | struct C {
| | B m_b;
| | }
| |
| | A C::*p = &C::m_b;
| |
| | The last assignement produces a compiler error in MVC:
| | "cannot convert from 'class B C::*' to 'class A C::*'".
[...]
| I would guess that the reasoning behind this is that pointers to members
| are *not* pointers to objects.
So? The conversion in question still makes sense, and would be perfectly
safe, wouldn't it? Wouldn't it therefore make sense to allow such
conversions?
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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: Vladimir Neyman <Vladimir_Neyman@stratus.com>
Date: 1996/04/29 Raw View
OK, I got it wrong. The draft standard is quite clear in
distinquishing between pointers TO class and pointers INTO
class, but I read it incorrectly. So, $4.11 does not say anything
about possible conversions between types (Base C::*) and (Derived
C::*). I did not find anything about such conversions in other
parts of the standard, either. So, we should assume that such
conversions (in either direction) are prohibited.
Still, the rational of this decision eludes me. It seems that
conversion from Derived C::* to Base C::* would be safe, and it
seems to be in spirit of C++. (If we are allowed to make such
conversion after we have an object of class C, why prohibit it on
pointer to member level?).
BTW, I am sorry for my original duplicate posting. My newsreader
gave me an error on my first posting attempt, so I assumed that
it was unsuccessful, although it was not!
- Vladimir
---
[ 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: oliva@dcc.unicamp.br (Alexandre Oliva)
Date: 1996/04/30 Raw View
Vladimir Neyman writes:
> [...] a pointer to a base class is
> convertable to a pointer to a derived class. The standard says that
> this inversion of normal rules is necessary for type safety.
> Does anybody know why this inversion is necessary for type safety?
> Is it safe to do explicit typecast from 'class B C::*' to 'class A
> C::*' in the above example?
Suppose the following hierarchy:
class A {};
class B : public A { public: int foo; }
class C : public A {};
B bar;
C car;
int A::*foop = &(B::foo) // this is not valid C++!
int bad = car.*foop; // Cs do not contain a B::foo
The point is that any A::* is certainly a valid B::* also, but the
converse does not hold, as I hope I have just shown.
--
Alexandre Oliva
oliva@dcc.unicamp.br
Universidade Estadual de Campinas, S~ao Paulo, Brasil
[ 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: jason@cygnus.com (Jason Merrill)
Date: 1996/04/30 Raw View
>>>>> Fergus Henderson <fjh@mundook.cs.mu.OZ.AU> writes:
> JdeBP@jba.co.uk (Jonathan de Boyne Pollard) writes:
> | Vladimir Neyman (Vladimir_Neyman@stratus.com) wrote:
> | | class A {};
> | |
> | | class B : public A {};
> | |
> | | struct C {
> | | B m_b;
> | | }
> | |
> | | A C::*p = &C::m_b;
> | |
> | | The last assignement produces a compiler error in MVC:
> | | "cannot convert from 'class B C::*' to 'class A C::*'".
> [...]
> | I would guess that the reasoning behind this is that pointers to members
> | are *not* pointers to objects.
> So? The conversion in question still makes sense, and would be perfectly
> safe, wouldn't it? Wouldn't it therefore make sense to allow such
> conversions?
No. A 'B C::*' is more akin to a 'B**' than a 'B*', as it refers to an
offset within a C, rather than to a B directly. Just as you can't convert
a 'B**' to an 'A**', you can't convert a 'B C::*' to an 'A C::*'.
Jason
---
[ 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: ark@research.att.com (Andrew Koenig)
Date: 1996/05/01 Raw View
In article <3184D6E8.1606@stratus.com> Vladimir Neyman <Vladimir_Neyman@stratus.com> writes:
> Still, the rational of this decision eludes me. It seems that
> conversion from Derived C::* to Base C::* would be safe, and it
> seems to be in spirit of C++.
But it is not safe, because a member of Derived is not necessarily
a member of Base. The conversion in the other direction is safe.
--
--Andrew Koenig
ark@research.att.com
[ 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: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1996/05/01 Raw View
jason@cygnus.com (Jason Merrill) writes:
> Fergus Henderson <fjh@mundook.cs.mu.OZ.AU> writes:
>> JdeBP@jba.co.uk (Jonathan de Boyne Pollard) writes:
>> | Vladimir Neyman (Vladimir_Neyman@stratus.com) wrote:
>> | | "cannot convert from 'class B C::*' to 'class A C::*'".
>> [...]
>> | I would guess that the reasoning behind this is that pointers to members
>> | are *not* pointers to objects.
>
>> So? The conversion in question still makes sense, and would be perfectly
>> safe, wouldn't it? Wouldn't it therefore make sense to allow such
>> conversions?
>
>No. A 'B C::*' is more akin to a 'B**' than a 'B*', as it refers to an
>offset within a C, rather than to a B directly. Just as you can't convert
>a 'B**' to an 'A**', you can't convert a 'B C::*' to an 'A C::*'.
Converting a `B**' to an `A**' is unsafe, because a `B*' is not an `A*'
and cannot be interpreted as such without a possibly representation-
changing conversion. In particular, in the case of multiple
inheritence some such conversions must be representation-changing.
In other words, converting a `B**' to an `A**' could require modifying
not just the `B**' value, but also what it points to, and this is
obviously undesirable and unworkable.
However, I don't think the same issue arises in the case of converting
`Derived C::*' to `Base C::*'. Remember, pointers to data members
can be represented as simple offsets. For example, if you have
struct Base1 { int a, b; }; // assume sizeof(Base1) == 8
struct Base2 { int c; }; // assume sizeof(Base2) == 4
struct Derived :
Base1, // assume offset 0
Base2 // assume offset 8
{ int d, e; }; // assume sizeof(Derived) == 16
struct C {
int x; // assume offset 0
Base y; // assume offset 4
Derived z1; // assume offset 12
Derived z2; // assume offset 28
};
then an initialization such as
Derived C::*pm1 = &C::z;
simply stores (a representation of) the offset 12 in `pm1'.
To implement
Base1 C::*pm2 = pm1;
no representation change is needed, since the offset of `Base1' in
`Derived' is zero. To implement
Base2 C::*pm2 = pm1;
all that an implementation would need to do is to add the offset
of `Base2' in `Derived' from the offset stored in `pm1', and put the
result in `pm2'. In this case, the offset of `Base2' in `Derived' is 8,
and 12 + 8 = 20, so the offset stored in pm2 would be 20.
(The implementation must do a little fancy footwork in all of this to
handle null pointers-to-members.)
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1996/05/01 Raw View
ark@research.att.com (Andrew Koenig) writes:
>Vladimir Neyman <Vladimir_Neyman@stratus.com> writes:
>
>> Still, the rational of this decision eludes me. It seems that
>> conversion from Derived C::* to Base C::* would be safe, and it
>> seems to be in spirit of C++.
>
>But it is not safe, because a member of Derived is not necessarily
>a member of Base. The conversion in the other direction is safe.
We're talking about members of `C', not members of `Derived' or `Base'.
In words, conversion from `Derived C::*' to `Base C::*' is converting
from a pointer to a member of class `C' whose type is `Derived',
to a pointer to a member of class `C' whose type is `Base'.
Why is this unsafe?
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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: JdeBP@jba.co.uk (Jonathan de Boyne Pollard)
Date: 1996/05/01 Raw View
Andrew Koenig (ark@research.att.com) wrote:
| In article <3184D6E8.1606@stratus.com> Vladimir Neyman <Vladimir_Neyman@stratus.com> writes:
|
| > Still, the rational of this decision eludes me. It seems that
| > conversion from Derived C::* to Base C::* would be safe, and it
| > seems to be in spirit of C++.
|
| But it is not safe, because a member of Derived is not necessarily
| a member of Base. The conversion in the other direction is safe.
Time to clean your reading glasses Andrew. (-:
The two p-t-ms are both pointers to members of the _same_class_, class C.
The question is whether a p-t-m of class C, that has type Derived, should
be freely convertible to a p-t-m of class C, that has type Base. Currently
there is no standard conversion that allows this.
Maybe some sample source would make this clearer.
class Base {} ;
class Derived : public Base {} ;
class C {
Derived d ;
} ;
Derived C::*ptr_to_d_member = &C::d ;
Base C::*ptr_to_b_member = &C::d ; // Currently ill-formed
As I was saying before, my guess at the rationale for not allowing such a
conversion is that the p-t-ms are not pointers to objects, only pointers to
members. One needs an object of class C before the p-t-ms can be turned
into pointers to objects. At which time, the standard pointer conversions
can apply, and there's not a problem.
C c_object ;
Derived * ptr_to_d = &c_object.*ptr_to_d_member ;
Base * ptr_to_b = ptr_to_d ;
Now it *could* be argued that p-t-m conversions of this kind are safe
(by analogy with the standard pointer conversion from `Derived *' to `Base
*' being safe), and that a `Derived C::*' should thus be freely convertible
to a `Base C::*'. This would give us data member object slicing.
C c_object ;
Base C::*ptr_to_b_member = &C::d ; // Currently ill-formed
Base * ptr_to_b_subobject = &c_object.*ptr_to_b_member ;
But that argument I shall leave to someone else. I've never desired this
myself.
---
[ 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: ball@eng.sun.com (Mike Ball)
Date: 1996/05/01 Raw View
In article 5d3@mulga.cs.mu.OZ.AU, fjh@mundook.cs.mu.OZ.AU (Fergus Henderson) writes:
>
> We're talking about members of `C', not members of `Derived' or `Base'.
> In words, conversion from `Derived C::*' to `Base C::*' is converting
> from a pointer to a member of class `C' whose type is `Derived',
> to a pointer to a member of class `C' whose type is `Base'.
> Why is this unsafe?
It's safe, but it's expensive if virtual bases are involved in any way, since
you need an actual instance of the class to do the cast. This means that you
have to save up all of the casts then do them after you have dereferenced
the pointer to member itself. When we discussed this in the working group this
we decided that the amount of mechanism was probably unjustified for such a
small gain in generality.
---
Michael Ball
SunSoft Development Products
---
[ 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: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1996/05/02 Raw View
ball@eng.sun.com (Mike Ball) writes:
>fjh@mundook.cs.mu.OZ.AU (Fergus Henderson) writes:
>>
>> We're talking about members of `C', not members of `Derived' or `Base'.
>> In words, conversion from `Derived C::*' to `Base C::*' is converting
>> from a pointer to a member of class `C' whose type is `Derived',
>> to a pointer to a member of class `C' whose type is `Base'.
>> Why is this unsafe?
>
>It's safe, but it's expensive if virtual bases are involved in any way, since
>you need an actual instance of the class to do the cast. This means that you
>have to save up all of the casts then do them after you have dereferenced
>the pointer to member itself. When we discussed this in the working group
>we decided that the amount of mechanism was probably unjustified for such a
>small gain in generality.
OK, thanks for the explanation. You're quite right about the implementation
difficulties when virtual base classes are involved - in my previous post
outlining a possible implementation I failed to consider that case.
This makes a very reasonable rationale for disallowing these conversions.
I guess it would be possible to allow the conversions only for non-virtual
base classes, but that would probably be too tricky -- it's better to
disallow them all.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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 ]