Newsgroups: comp.lang.c++
From: vadim@cix.compulink.co.uk (Vadim Lebedev)
Subject: Re: Object metamorphosis - can
Reply-To: vadim@cix.compulink.co.uk
Date: Wed, 19 Aug 1992 16:44:38 +0000


TITLE: Object metamorphosis - can/should it be done?

In article   : <1992Aug17.223629.5722@fcom.cc.utah.edu>
 swillden@news.ccutah.edu (Shawn Willden)
 writes:
> 
> I ran across some interesting Objective-C code the other day and I 
> wondered if there is some way to implement it in C++.  Then I wondered
> if it was a good idea to try.  Anyway, the concept is that an object
> can be asked to mutate into an object of a different type.  Under
> Objective-C's concept of an object, any object can mutate to essentially
> any other type because all messages are resolved at run-time.  In C++'s
> static system this is not possible, however, it seems to me that there 
> is at least one case in which it might be possible in C++ and maybe even 
> useful.  Given a base class pointer or reference to a derived class
> object, it should be possible to replace the derived class object with
> an object of another derived type.  Something like:
[ message deleted]

You canc achieve your goal using placement new syntax:

class Mutator { } mutator;

class Butterfly
        {
 protected:
    // Allocate abject in-place 
    void *new(size_t,  void *t)  { return t; }
    
    // Mutating constructor
    Butterfly(Mutator , const Butterfly &) { // Do nothing here }

        // some data here.
        public:

 // allocate a storage chunk capable to accomodoate all of the 
 // variantes 
 void *new(size_t s) {
  return new char[MAX(sizeof(Pupa), sizeof(Adult), sizeof(Butterfly),s)];
  }

        Butterfly()                     {...}
        Butterfly(Butterfly& b)         {...}
        // The metamorphose() function will turn an object of some
        // descendant type into an object of some other descendant 
        // type.
        virtual void metamorphose() = 0;
        virtual void report()           {cout << "I'm a generic butterfly\n";}
        };

class Pupa : public Butterfly
        {
        // Note that this method is private.  This is to insure that
        // it is *only* called through the base class interface. 
        void metamorphose();
        public:
        Pupa()                  {...}
        void report()           {cout << "I'm a caterpillar\n";}
 protected:
    // Mutating constractor
    Pupa(Mutator m, const Butterfly &b) : Butterfly(m, b) { }  
        };

class Adult : public Butterfly
        {
friend class Pupa;
        // Again, this method is private.
        void metamorphose();
        public:
        Adult()                                 {...}
        Adult(Butterfly& b) : Butterfly(b)      {...}
        void report()           {cout << "I'm a real butterfly\n";}
 protected:
    Adult(Mutator m, const Pupa &p) : Butterfly(m, p) { }  

        };

void Pupa::metamorphose()
        {
 new (this) Adult(mutator, *this);
        }

main()
        {
        Butterfly *fred = new Pupa;

        fred->report();
        fred->metamorphose();
        fred->report();
        }


Of course this trick works only on heap allocated objects, for automatic
or static objects one should take care that the base and all derived classes
has the same sizes. 

-----------------------------------------------------------------------
Vadim Lebedev                      |   Kortex International
vadim@cix.compulink.co.uk          |   139-147 av. Paul-Vaillant Couturier
                                   |   93126 La Courneuve - CEDEX, France