class system setup

J

Jürgen Böhm

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::eek: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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,131
Latest member
IsiahLiebe
Top