[comp.lang.c++] Re problems with vtables

aed@netcom.COM (Andrew Davidson) (02/07/91)

Hello

I found an interesting anomaly when trying to implement a 
way to change the Vtable of an object. 


I have a ChangeModel() function 

	void ChangeModel(Bond &b)
	{
  	noop x;
  	new(&b) UsersBond(x); // turns bond in to UsersBond
	}

The problem I found is that if the object being passed to
the function is on the stack that the Vtable is only changed
with in the scope of the ChangeModel() function. as soon as
this function returns, the object uses its original vtable?

But if the object being passed is on the heap the vtable is changed
both in the ChangeModel() function scope and the scope of the
calling function.

Could this be a bug with turbo C++, or am I missing something?
(hopefully my Sys Admn will install my AT&T compiler, but I have
already been waiting for over 6 months). I first tried this program
with g++ 1.37.0, but gnu would not compile.

thanks Andy


here is the out put 

id: 1 amount: 10 npv: 20
id: 1 amount: 10 npv: 30
id: 1 amount: 10 npv: 30
id: 2 amount: 20 npv: 40
id: 2 amount: 20 npv: 60
id: 2 amount: 20 npv: 40

here is the Source 
------------------------- cut here ---------------------------
/*
 * by A. E. Davidson
 *
 * ref
 * CHANGING OPERATIONS" page 17
 * in Bjarne Stroustrup`s article "Sixteen ways to stack a cat, part 2"
 * in Vol 2 Number 10 nov/dec 1990 The C++ Report
 *
 * the purpose of this example is to show a way to
 * change a bond objects CalcNpv() member function
 */


#include <iostream.h>

class noop
{};

class Bond;
void* operator new(size_t,void *p);
void ChangeModel(Bond &b);

/*
 * Tran is used as a base class
 */
class Tran
{
 public:
  virtual ~Tran() {;} 
  virtual void CalcNpv() = 0; 
  virtual void Display() = 0;
  
 protected:
  int npv;
  int id;
  static int nextAvailTranId;
  Tran(noop x) 
    {;} 
  Tran() 
    { id = nextAvailTranId++; npv = 0; } 
};

/*
 * application defined object
 * contains a default princing model
 * CalcNpv()
 */
class Bond : public Tran 
{
 public:
  Bond(int value = 0) 
    : Tran() {amount = value; CalcNpv(); }
  Bond(noop x)	/* make an unitialized bond */
    : Tran(x) {;} 
  ~Bond() 
    {;}
  void Display()
    { cout << "id: " << id << " amount: " << amount << " npv: " << npv <<"\n"; }
  void CalcNpv()
      { npv = amount * 2; }

 protected:
  int amount;
};

/*
 * bogus class provide
 * so that user can define
 * his own pricing formula
 * with in our application
 * frame work
 */
class UsersBond : public Bond
{
 public:
  UsersBond(noop x): Bond(x){;}
  void CalcNpv()
      { npv = amount * 3; }
};

int Tran::nextAvailTranId = 1;


/*
 * changes a bond object into
 * a UsersBond object
 * note
 * the representation of the
 * objects is not changed
 * all that is changed are
 * the virtual functions
 */
void ChangeModel(Bond &b)
{
  noop x;
  new(&b) UsersBond(x); // turns bond in to UsersBond
  
  /*
   * test to see if vtable is change with in
   * function scope
   */
  b.CalcNpv();
  b.Display();

}

void* operator new(size_t,void *p){return p;}

main()
{
  Bond *b1 = new Bond(10);
  Bond b2(20);
  
  b1->CalcNpv();    // 10 * 2 */
  b1->Display();
  ChangeModel(*b1); // change the virtual member functions for b1
  b1->CalcNpv();    // should be 10 * 3
  b1->Display();

  b2.CalcNpv();    // 20 * 2
  b2.Display();
  ChangeModel(b2); // change the virtual member functions for b2
  b2.CalcNpv();    // should be 20 * 3
  b2.Display();
}



-- 
-----------------------------------------------------------------
                  "bede-bede-bede Thats all Folks"
				Porky Pig
Andy Davidson
Woodside CA.
aed@netcom.COM
-----------------------------------------------------------------