[comp.lang.c++] Need help setting up uNmber class in C++

cotner@brahms.berkeley.edu (Carl Cotner) (10/28/89)

I'm a beginner to C++ as well as to this newsgroup, so please bear with me 
if what I'm asking seems trite and trivial.  I don't have the hang of
programming in an object-oriented manner yet, but I'm trying.

What I would like to do is define a class called Number which can
automatically perform operations (+,-,*,/) on several types and convert
to and from each one transparently.  Sound like a familiar problem?
(Then why am I having so much trouble implementing it!)  

My goal in the end is to develop numerical analysis programs in which I 
define functions that use this class, like so:

	Number func1(Number &x)
	{
	   Number y = 1/(x*x + 1);
	   return y;
	}

Now it shouldn't matter whether I pass in a real, complex, int, double, or
rational represented within Number.  The Number object y performs the 
operations and type conversions automatically. If Number x had originally
contained an int, a double would have been returned.  If x were a complex
int, then a complex double should be expected.

The types that I would like to be represented are:

	int, double, complex int (both real and imaginary parts are int's), 
	complex double, and rational (representing numerator and 
	denominator as 2 ints's)

and perhaps keep the door open for future types such as quad and complex 
quad.

Okay how do I do this?

My first impulse was to define each type as a separate class and have 
Number contain a pointer to them.

	enum { INT=0, DBL, CINT, CDBL, RAT } Ntype;

	class NumObj {
	  Ntype NumType;	//this is just the base class
	public:
	  void setType(nt) { NumType = nt; }
	  Ntype getType() { return NumType; }

	  virtual void print() { cerr << "print should be bound\n"; }
	  virtual void getnval(void **num)
		{ cerr << "getnval should be bound\n"; }
	  virtual void setnval(const void *num)
		{ cerr << "setnval should be bound\n"; }
	}

// We then derive a new class to represent each type
	class Int : public NumObj {
	  int a;
	public:
	  Int() { setType(INT); }
	  Int(int v) : a(v) { setType(INT); }
	  void getnval(void **num) { *num = new int;
		*(int *)*num = a; }
	  void setnval(void *num) { a = *(int *)num; }
	  void print() { cerr << a << "\n"; }
	  operator Int +(const CInt& B) { return Int(a + B.a); }
	}

// Similarly we have the rest of the types
	class Cdbl : public NumObj {
	  double u,v;
	public:
	  Cdbl(double u, double v) : a(u), b(v) { setType(CDBL); }
 	  ...
	}

Then Number class would then be 

	class Number {
	  NumObj *Nptr;		// pointer to base class for each type
	public:
	  Number(int a) { Nptr = new Int; Nptr->setval( a ); }
	  Number(double a, double b) { Nptr = new Cdbl;
		Nptr->setval(a,b); }
	  void print() { cout << "Number = "; Nptr->print(); }
	  friend Number operator +(Number &A, Number &B);
	}
The getnval()/setnval() routines are used for passing data to and from
each of the types using a consistent prototype; typically one would do
something like this to convert from int to double:
		void *val;
		Nptr->getnval( &val ); 	// get say an int 
					// now perform conversion
		double newval = double( *(int *)val );
		val = newval;
		setnval( &val );	
		
Form here on, I start becoming confused and dazed as I try to define and
implement the conversion routines between each separate type class and
Number, as well as define the  binary operations + - * /.  
About the onlything that works is print().
		Nptr->print(); 
works just fine.

How should I  go about setting up this class?  I've tried several
attempts but I just seem to end up with awkward code.


One final question:  Assuming this Number class works and is the right way
to go, I would like to start writing up routines such as

	NewtonRaphson( Number(*function)(), Point StartPt )
	{


	}

Ie, have a generic numerical technique, as one would have a generic 
stack or queue.

My question, is this also the correct way to go about it?  That is, 
should I be passing in a pointer to a function,  or should I set up 
NewtonRaphson as a class, declare a virtual function which I then 
define at run-time?

From the gist of these questions you may deduce that I still have a lot
to learn about C++ and OOPS.  Any suggestions for how I can become better
educated?


Thanks
Carl

cotner@brahms.Berkeley.EDU

ucbvax!brahms!cotner	           Carl Cotner/UCB Math Dept/Berkeley CA 94720