From: swillden@news.ccutah.edu (Shawn Willden)
Subject: Object metamorphosis - can/should it be done?
Organization: University of Utah Computer Center
X-Newsreader: Tin 1.1 PL3
Date: Mon, 17 Aug 92 22:36:29 GMT

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:

class Butterfly
	{
	// some data here.
	public:
	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";}
	};

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

void Pupa::metamorphose()
	{
	Pupa* old_me = this;
	(Adult*)this = new Adult(*old_me);
	delete old_me;
	}

main()
	{
	Butterfly *fred = new Pupa;

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

with the desired output being, of course:
I'm a caterpillar
I'm a real butterfly

Obviously there are a few holes in my example (like what if the Pupa being
asked to metamorphose was automatically allocated and I delete it).  GCC
won't let me actually DO this (it complains heartily about any assignments
to this) and while it let me compile something like this:

void Pupa::change(void*& p)
	{
	p = (void*)new Adult((Pupa*)p);
	}

void Pupa::metamorphose()
	{
	Pupa* old_me = this;
	change((void*)this);
	delete old_me;
	}	

the output was:
I'm a caterpillar
I'm a caterpillar

I haven't bothered compiling to assembly to figure out exactly why it doesn't
do what I want it to, but it's clear that it doesn't.

So, some questions:
	1)	Is there any way to make this work (portably or unportably).
	2)	Why is this a bad idea?  Or is it?
	3)	Suppose I REALLY wanted to do this.  Are there better ways 
		that don't require me to play tricks with the type system?
		One way to get the same effect (the one that comes to my mind
		first) is to make a class Butterfly that contains a `state'
		variable that is changed by the metamorphose() method and
		switched on by report() and its ilk.  Any other suggestions?
	
Shawn Willden
swillden@icarus.weber.edu	
Newsgroups: comp.lang.c++