Topic: A hole in the type system?


Author: pabloh@hpwala.wal.hp.com (Pablo Halpern )
Date: Fri, 5 Nov 1993 20:16:02 GMT
Raw View
In article <9329916.12036@mulga.cs.mu.OZ.AU>, fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:
|> >John Max Skaller argues that you also can leave it by abusing
|> >inheritance - something that isn't clearly visible in the source text.
|>
|> I think that you may have mis-interpreted what he was saying.
|> I think he was saying that it had a well-defined meaning, i.e.
|> that by using it you remain in the "closed, safe universe".
|> [The ARM does indeed guarantee that the meaning remains well-defined
|> for compiler-generated assignment operators (ARM 12.8, page 298).]
|> The problem is just that this well-defined meaning might not
|> be the meaning that you wanted.  In particular if operator=()
|> is not virtual, then it probably won't be the meaning you wanted.

Several times in this thread I have seen mention of making operator=
virtual.  OK, yes, if you call any function (including operator=) on a
base-class view of a derived-class object, then the only way you can expect
correct behavior is to make the function virtual.  Unfortunately, what this
means is that you have to override the assignment operator for ALL of your
base classes:

  class Base { /* ... */ };

  class Derived : public Base  { /* ... */ };

  class Leaf : public Derived
  {
  public:
    virtual Base&    operator=(const Base& b);
    virtual Derived& operator=(const Derived& d);
    virtual Leaf&    operator=(const Leaf& lf);
    // ...
  };

The overriding functions could either raise an exception ;^) or do
something intelligent about derived-class members not found in the base
class.  Hmm...  programming with classes is even harder than I thought ;-)
Perhaps we need multiple-dispatch to solve this elegantly (no flames,
please!).

--
- Pablo

-------------------------------------------------------------------------
Pablo Halpern          Permanent:  (508) 435-5274   phalpern@world.std.com
                       Thru 10/93: (508) 659-4639   pabloh@wal.hp.com
                       (Send mail to either address)
-------------------------------------------------------------------------




Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Mon, 1 Nov 1993 06:28:09 GMT
Raw View
In article <HF.93Oct20165659@loophole.informatik.uni-karlsruhe.de> hf@informatik.uni-karlsruhe.de (Harald Fuchs) writes:
>Consider the following code:
>
>1  struct A {};
>2  struct B: A {};
>
>3  A a;
>4  B b;
>5  b = a;
>6  A& ra = b;
>7  ra = a;
>
>At line 5 we try to assign an A object to a B object, which is illegal
>(and rightly so).
>At line 6 and 7 we try to do the same by means of a reference to A. I
>didn't find anything in the ARM which would prohibit this, and none of
>the five compilers I tried complained. All of them overwrote the A
>portion of the B object referred to by `ra'.

Be careful.  Such assignments do indeed overwrite all of the user-declared
data members of the A portion of the B object, but such assignments SHOULD
NOT overwrite the "identity" portion of the A portion of the B object (i.e.
the virtual function pointer table pointer... if one is present).

In other words, after such an assignment, the B object must still *act*
like a B object (as far as virtual functions are concerned) after the
assignment.

(Of course that's not explicitly documented anywhere, but then it doesn't
have to be.  It is only of significance to implementors.  Mere end users
only need to know that such assignments have no effect upon the "dynamic
type" of the target object... but then nobody ever said that such an
assignment *would* have an effect upon the type identity of the target
object... so by default, you should just assume that it doesn't; which
is correct.  It doesn't.)

--

-- Ronald F. Guilmette, Sunnyvale, California -------------------------------
------ domain address: rfg@netcom.com ---------------------------------------
------ uucp address: ...!uunet!netcom.com!rfg -------------------------------