Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!gem.mps.ohio-state.edu!apple!agate!brahms.berkeley.edu!cotner From: cotner@brahms.berkeley.edu (Carl Cotner) Newsgroups: comp.lang.c++ Subject: Need help setting up uNmber class in C++ Keywords: Number C++ class Message-ID: <1989Oct28.013848.23692@agate.berkeley.edu> Date: 28 Oct 89 01:38:48 GMT Sender: cotner@brahms.berkeley.edu (Carl Cotner) Reply-To: cotner@brahms.berkeley.edu (Carl Cotner) Organization: University of California, Berkeley Lines: 136 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