class system setup
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::operator-> {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