Hello,

(I already posted this at comp.lang.c++.moderated, but received no

answers, maybe it is better placed here?):

to implement a little symbolic computation system, dealing with

Polynomials, arbitrary long Integers, symbolic variables, hash tables

and other relevant stuff I set up a certain scheme of classes in the

following form:

A class system of "Types" having as base class

class Expr {

....

ExprRep *rep;

}

and derived classes

Variable: public virtual Expr for variables

RingElem: public virtual Expr for all ring elements

Integer: public RingElem for long integers

Rational: public RingElem for rationals

To every class X of this hierarchy corresponds a class Xrep which gives

its concrete implementation. So the "Types" hierarchy classes X are

"Envelope" classes, the Xrep are "Letter" classes.

So in the above example we have:

ExprRep

VariableRep: public ExprRep

RingElemRep: public ExprRep

IntegerRep: public RingElemRep

RationalRep: public RingElemRep

The functions that apply for a type X are provided in Xrep, sometimes as

virtual functions, for example in RingElemRep, there is

virtual RingElem add(const RingElem& b)

which is repeated and concretized in IntegerRep.

The "type"-classes delegate their functions via overloaded operator->,

that is, for example, Variable contains

VariableRep* getRep () {

return dynamic_cast<VariableRep*>(Expr::getRep()); }

VariableRep* operator-> {return getRep(); }

with Expr::getRep() being

ExprRep* getRep() { return rep; };

In general every "type"-class X contains

XRep* getRep () { return dynamic_cast<XRep*>(Expr::getRep()); }

XRep* operator-> {return getRep(); }

The advantage of this setup seems to me, that there need not be a fat

interface in ExprRep, offering all functions in all derived classes from

ExprRep.

With this setup I can write

Variable v("x");

Integer i(7);

i->add(i) // ok, calls IntegerRep::add(const RingElem& b)

v->add(i) // error, no add method in VariableRep

Additionally there is in every "type"-class X a pseudo-copy constructor

X(const Expr& e) {rep = dynamic_cast<XRep*>(e.rep);}

(actually there is reference counting added)

This allows type checking and dynamic typing

Variable v("x");

Integer i(7);

Expr ei = i;

Expr ev = v;

f(Integer j) { cout << j; }

f(i) // ok

f(v) // error

(v gets interpreted as Expr, then Integer(const Expr& e) as described

above is tried, but rep of v points to a VariableRep which can not be

dynamic casted to an IntegerRep*).

f(ei) // ok

f(ev) // error

So far so good(?). As I am not that experienced in C++ I would first

appreciate to hear some critique of this approach and second pose a

specific question: As mentioned above there are some functions that

repeat themselves in varied form in every "type"-class, namely

XRep* X::getRep () { return dynamic_cast<XRep*>(Expr::getRep()); }

XRep* X:

perator-> {return getRep(); }

X::X(const Expr& e) {rep = dynamic_cast<XRep*>(e.rep);}

where X is the "type"-class. Currently I handle this with a #define

macro to save me from typing, but is there a way in C++ to do this

without macros. I tried some schemes with templates and derivation but

it never worked out...

Greetings

Jürgen

--

Jürgen Böhm

www.aviduratas.de
"At a time when so many scholars in the world are calculating, is it not

desirable that some, who can, dream ?" R. Thom