Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   class system setup (http://www.velocityreviews.com/forums/t620273-class-system-setup.html)

Jürgen Böhm 06-15-2008 01:24 AM

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


All times are GMT. The time now is 11:08 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.