Thread View: comp.std.c++
6 messages
6 total messages
Started by Jean-Rene Bouvier
Mon, 25 Sep 1995 07:25
Inheritance and references to pointers
Author: Jean-Rene Bouvier
Date: Mon, 25 Sep 1995 07:25
Date: Mon, 25 Sep 1995 07:25
52 lines
2668 bytes
2668 bytes
In a number of libraries, the following trick is used to denote the acquisition
of a pointer and to make it inaccessible to callers:
void GrabPointer(Object*& object)
{
Object* obj = object;
object = 0;
// Now, work with obj ...
}
Callers who pass pointers to GrabPointer() will not be able - upon return from
the function - to access the object the pointer used to refer to.
This nice trick is defeated in presence of inheritance; i.e. if instead of
passing an Object*, the caller wants to pass a DerivedObject*, a compilation
error should be issued (at least, this is my understanding, and this is also
what Borland 4.5 and HP 3.5 compilers do).
This is very unfortunate, and it also makes the use of references to pointers
counter-intuitive: after all, if a reference hadn't been used, passing a
DerivedObject* would have been perfectly legal.
My questions thus are:
1. is my understanding correct (i.e. that a DerviedObject*& cannot be passed
in lieu of an Object*&) ?
2. what is the reason for this restriction, or rather, is there any reason to
keep this restriction (apart from the fact that a DerviedObject*& bears no
inheritance relationship to an Object*&) ?
3. More generally, why isn't there a generalization of the fact that:
DerivedObject can be passed to a function expecting an Object (slicing),
DerivedObject* can be passed to a function expecting an Object*,
DerivedObject& can be passed to a function expecting an Object&,
so that further indirections/references would be allowed:
DerivedObject** could be passed to a function expecting an Object**,
DerivedObject*& could be passed to a function expecting an Object*&,
DerivedObject*** could be passed to a function expecting an Object***,
... ?
Email replies are welcome (to: jr@grenoble.hp.com)
Thanks,
- jr
[jean-rene bouvier]
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: Inheritance and references to pointers
Author: Andrew Koenig
Date: Tue, 26 Sep 1995 06:53
Date: Tue, 26 Sep 1995 06:53
23 lines
1432 bytes
1432 bytes
In article <445k3k$18p@isoit109.bbn.hp.com> Jean-Rene Bouvier <jr@isoit109.bbn.hp.com> writes: > 2. what is the reason for this restriction, or rather, is there any reason to > keep this restriction (apart from the fact that a DerviedObject*& bears no > inheritance relationship to an Object*&) ? The real problem is that a DerivedObject* might not have the same internal representation (i.e. bit pattern) as an Object*, because there is no reason to believe that the Object part of a DerivedObject is at the beginning of the DerivedObject. In the presence of multiple inheritance, we can guarantee that a DerivedObject* will have a different representation from a pointer to at least one of its base classes. -- --Andrew Koenig ark@research.att.com --- [ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu. Contact address: std-c++-request@ncar.ucar.edu. The moderation policy is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: Inheritance and references to pointers
Author: Alex Martelli
Date: Tue, 26 Sep 1995 15:13
Date: Tue, 26 Sep 1995 15:13
76 lines
3398 bytes
3398 bytes
Jean-Rene Bouvier <jr@isoit109.bbn.hp.com> writes:
...
>1. is my understanding correct (i.e. that a DerviedObject*& cannot be passed
> in lieu of an Object*&) ?
>2. what is the reason for this restriction, or rather, is there any reason to
> keep this restriction (apart from the fact that a DerviedObject*& bears no
> inheritance relationship to an Object*&) ?
...
> DerivedObject** could be passed to a function expecting an Object**,
It would violate type-safety. It may be easier to see with pointers to
pointers:
class B {
public:
// whatever
};
class D: public B {
public:
void aMethodOnlyDhadAnd_NOT_B();
// whatever else
};
B b;
void tricky(B ** pointer_to_pointer)
{
*pointer_to_pointer = &b;
}
void ingenue()
{
D d;
D* pd = &d;
tricky(&pd);
pd->aMethodOnlyDhadAnd_NOT_B();
}
Can you see that type safety is "transparently" violated? Without
any cast or other unsafe construct, JUST because this hypothetical
version of the C++ language allows passing a D** where a B** is
expected, poor ingenue() function finds itself with a content for
pd which is *NOT* a pointer-to-D! Then of course it uses pd as
if it WAS a pointer to D (why shouldn't it?!), and, ka-BOOM!
If we were talking about references to pointers, the only difference
would of course be to have the type-safety hole even more hidden
and transparent... So, clearly, the above code snippet needs a
compile-time error somewhere -- and where could that be, except
in the argument-type-mismatch between the declaration of tricky()
and the call to it?
This is, in a way, related to of the old problem that a bag-of-apples
is-NOT-a bag-of-fruit (even if an apple is-A fruit) *under mutation*
(because if you passed it to a function treating it as bag-of-fruit,
it could insert in it a banana, thus violating semantic constraints
[class invariants] of bag-of-apples). [_that_, in turn, can be more
abstractly related to the problem that a circle is-NOT-an ellipse
*under mutation*, because a rescale(mX,mY) would violate the semantic
symmetry constraint of class circle...]. The presence of mutators
makes is-A determinations far from intuitive sometimes...!
Alex
--
DISCLAIMER: these are TOTALLY personal opinions and viewpoints, NOT connected
in any way with my employer, nor any other organization or individual!
Email: martelli@cadlab.it Phone: +39 (51) 597313
CAD.LAB s.p.a., v. Ronzani 7/29, Casalecchio, Italia Fax: +39 (51) 597120
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: Inheritance and references to pointers
Author: John Max Skaller
Date: Wed, 27 Sep 1995 06:12
Date: Wed, 27 Sep 1995 06:12
63 lines
2973 bytes
2973 bytes
Jean-Rene Bouvier <jr@isoit109.bbn.hp.com> wrote:
>In a number of libraries, the following trick is used to denote the acquisition
>of a pointer and to make it inaccessible to callers:
>
> void GrabPointer(Object*& object)
> {
> Object* obj = object;
> object = 0;
> // Now, work with obj ...
> }
>
>Callers who pass pointers to GrabPointer() will not be able - upon return from
>the function - to access the object the pointer used to refer to.
>
>This nice trick is defeated in presence of inheritance; i.e. if instead of
>passing an Object*, the caller wants to pass a DerivedObject*, a compilation
>error should be issued (at least, this is my understanding, and this is also
>what Borland 4.5 and HP 3.5 compilers do).
>
>This is very unfortunate, and it also makes the use of references to pointers
>counter-intuitive: after all, if a reference hadn't been used, passing a
>DerivedObject* would have been perfectly legal.
Nope. The conversion
DerivedObject* --> Object*
is an RVALUE conversion. The resultant Object* is an rvalue.
You cannot bind a non-const reference (argument) to an rvalue.
Think about it -- setting the a pointer variable (lvalue) known as an
Object*
to some value inside the function, when the caller knew it as
an DerivedObject* variable, would require an adjustment to the pointer
in the general case: the called function cannot know that and the
generated code would be a simple register store operation.
The resultant value would not be usable in the callers environment.
Basically, a DerivedObject* is NOT derived from an Object*.
Solution -- overloading:
void GrabPointer(DerivedObject *& x) {
Object *o = x;
GrabPointer(o);
if(!o) x = 0;
}
[you might even try a template :-]
--
John Max Skaller voice: 61-2-566-2189
81 Glebe Point Rd fax: 61-2-660-0850
GLEBE NSW 2037 email: maxtal@suphys.physics.oz.au
AUSTRALIA email: skaller@maxtal.com.au
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: Inheritance and references to pointers
Author: Sam Fenster
Date: Wed, 27 Sep 1995 17:42
Date: Wed, 27 Sep 1995 17:42
32 lines
2094 bytes
2094 bytes
> Jean-Rene Bouvier <jr@isoit109.bbn.hp.com> writes:
>> 1. is my understanding correct (i.e. that a DerviedObject*& cannot be
>> passed in lieu of an Object*&) ?
martelli@cadlab.cadlab.it (Alex Martelli) writes:
> It would violate type-safety. It may be easier to see with pointers to
> pointers:
> B b;
> void tricky(B ** pointer_to_pointer)
> {*pointer_to_pointer = &b;}
>
> void ingenue()
> {D d; D* pd = &d; tricky(&pd); pd->aMethodOnlyDhadAnd_NOT_B();}
> This is, in a way, related to of the old problem that a bag-of-apples
> is-NOT-a bag-of-fruit (even if an apple is-A fruit) *under mutation*
> (because if you passed it to a function treating it as bag-of-fruit, it
> could insert in it a banana, thus violating semantic constraints [class
> invariants] of bag-of-apples). [_that_, in turn, can be more abstractly
> related to the problem that a circle is-NOT-an ellipse *under mutation*,
> because a rescale(mX,mY) would violate the semantic symmetry constraint of
> class circle...]. The presence of mutators makes is-A determinations far
> from intuitive sometimes...!
The fact that `D **' is-NOT-a `B **' is closely related to the fact that
`B **' is-NOT-a `const B **'. Both pairs fail because the referent of the
latter item can be mutated in ways not allowed by the former item.
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: Inheritance and references to pointers
Author: Jean-Rene Bouvier
Date: Thu, 28 Sep 1995 18:05
Date: Thu, 28 Sep 1995 18:05
58 lines
1923 bytes
1923 bytes
Distribution:
On the second question, I received a very good reason why it shouldn't be
legal,
from Johan Wikman (thanks!). Here it is:
>My question:
> 2. what is the reason for this restriction, or rather, is there any reason to
> keep this restriction (apart from the fact that a DerviedObject*& bears no
> inheritance relationship to an Object*&) ?
|Johan's response:
|
|Here's one good reason.
|
| class Object {};
| class DerivedObject {};
|
| void function(Object*& o)
| {
| o = new Object;
| }
|
| void anotherFunction()
| {
| DerivedObject* do;
|
| // If what you want would be allowed...
|
| function(do);
|
| // ... we would here have something that would walk,
| // feel and look like a DerivedObject although it
| // only is an Object.
| }
|
This should clarify the matter, as it answers also to question #1 and #3.
Note that there is a solution to writing the GrabPointer function,
which uses templates. Here it is:
template<class SomeDerivedObject>
void GrabPointer(SomeDerivedObject*& object)
{
Object* obj = object;
object = 0;
// work with obj ...
}
Borland 4.5 compiles and executes this correctly (I know, this doesn't prove
anything, but it's much more comfortable!).
jean-rene bouvier
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads