A design problem

A design problem

Post by Michael Li » Tue, 03 Sep 2002 20:15:30



Here's a problem I'm wrestling with:  I need to be able to easily define
classes that (1) store a private instance of a "Data" class,

    struct Data {
       ~Data();  // nonvirtual
       int value() const;
       /* ... other stuff ... */
    };

and that (2) "support" one or more sets of related operations (call them X1,
X2, ..., X9; Y1, Y2, ..., Y9; and so on), all of which can be implemented in
terms of the value returned by Data::value().  For example, a tedious way
is:

    void X1(int value);
    void X2(int value);
    // and so forth for X3, ..., X9, Y1, ..., Y9, ...

    class DataX {  // supports X operations only
       Data data;
    public:
       /* ... other stuff ... */
       void X1() const { ::X1(data.value()); }
       void X2() const { ::X2(data.value()); }
       // and so forth for X3, ..., X9.
    };

    class DataYZ {  // supports Y and Z operations only
       Data data;
    public:
       /* ... other stuff ... */
       void Y1() const { ::Y1(data.value()); }
       // and so forth for Y2, ..., Y9, Z1, ..., Z9.
    };

    class DataVWXYZ {  // supports V, W, X, Y, Z
       Data data;
    public:
       // ARGH!
    };

Is there a better design that minimizes the effort needed to create
additional Data**** classes (and that compiles under MSVC 6)?  Or is this
whole idea wrongheaded?

I've come up with two alternatives:

    template <class Base> class X : public Base {
    protected:
       X() { }
       ~X() { }
    public:
       void X1() const { do_X1(value()); }
       void X2() const { do_X2(value()); }
       // and so forth for X3, ..., X9.
    };
    // and similarly for class Y, class Z, ...

    class DataX : public X<Data> {
       /* ... other stuff ... */
    };

    class DataYZ : public Y< Z<Data> > {
       /* ... other stuff ... */
    };

    class DataVWXYZ : public V< W< X< Y< Z<Data> > > > > {
       /* ... other stuff ... */
    };

and

    template <class Derived> class X {
       int value() const {
          return static_cast<const Derived *>(this)->value();
       }
    protected:
       X() { }
       ~X() { }
    public:
       void X1() const { do_X1(value()); }
       void X2() const { do_X2(value()); }
       // and so forth for X3, ..., X9.
    };
    // and similarly for class Y, class Z, ...

    class DataX : public X<DataX> {
       Data data;
       int value() const { return data.value(); }
       friend class X<DataX>;
    public:
       /* ... other stuff ... */
    };

    class DataYZ : public Y<DataYZ>, Z<DataYZ> {
       Data data;
       int value() const { return data.value(); }
       friend class Y<DataYZ>;
       friend class Z<DataYZ>;
    public:
       /* ... other stuff ... */
    };

Comments?

Thanks!
Michael


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

A design problem

Post by Robert Klemm » Thu, 05 Sep 2002 01:16:42


you don't need templates:

//
// define interface
//
class DataHolder {
public:
  virtual Data& getData() = 0;
  // alternatively
  virtual int getDataValue() = 0;

Quote:};

//
// define operations
//
class OpX1 : public virtual DataHolder {
public:
  void X1() {
    int val = getData().value();
    // further ops
  }

Quote:};

class OpX2 : public virtual DataHolder {
public:
  void X2() {
    int val = getData().value();
    // further ops
  }

Quote:};

//
// create concrete classes
//
class Op : public OpX1, OpX2 {
  Data d;
public:
  virtual Data& getData() { return &d; }

Quote:}

you get the picture.

        robert

Michael Liu schrieb:

> Here's a problem I'm wrestling with:  I need to be able to easily define
> classes that (1) store a private instance of a "Data" class,

>     struct Data {
>        ~Data();  // nonvirtual
>        int value() const;
>        /* ... other stuff ... */
>     };

> and that (2) "support" one or more sets of related operations (call them X1,
> X2, ..., X9; Y1, Y2, ..., Y9; and so on), all of which can be implemented in
> terms of the value returned by Data::value().  For example, a tedious way
> is:

>     void X1(int value);
>     void X2(int value);
>     // and so forth for X3, ..., X9, Y1, ..., Y9, ...

>     class DataX {  // supports X operations only
>        Data data;
>     public:
>        /* ... other stuff ... */
>        void X1() const { ::X1(data.value()); }
>        void X2() const { ::X2(data.value()); }
>        // and so forth for X3, ..., X9.
>     };

>     class DataYZ {  // supports Y and Z operations only
>        Data data;
>     public:
>        /* ... other stuff ... */
>        void Y1() const { ::Y1(data.value()); }
>        // and so forth for Y2, ..., Y9, Z1, ..., Z9.
>     };

>     class DataVWXYZ {  // supports V, W, X, Y, Z
>        Data data;
>     public:
>        // ARGH!
>     };

> Is there a better design that minimizes the effort needed to create
> additional Data**** classes (and that compiles under MSVC 6)?  Or is this
> whole idea wrongheaded?

> I've come up with two alternatives:

>     template <class Base> class X : public Base {
>     protected:
>        X() { }
>        ~X() { }
>     public:
>        void X1() const { do_X1(value()); }
>        void X2() const { do_X2(value()); }
>        // and so forth for X3, ..., X9.
>     };
>     // and similarly for class Y, class Z, ...

>     class DataX : public X<Data> {
>        /* ... other stuff ... */
>     };

>     class DataYZ : public Y< Z<Data> > {
>        /* ... other stuff ... */
>     };

>     class DataVWXYZ : public V< W< X< Y< Z<Data> > > > > {
>        /* ... other stuff ... */
>     };

> and

>     template <class Derived> class X {
>        int value() const {
>           return static_cast<const Derived *>(this)->value();
>        }
>     protected:
>        X() { }
>        ~X() { }
>     public:
>        void X1() const { do_X1(value()); }
>        void X2() const { do_X2(value()); }
>        // and so forth for X3, ..., X9.
>     };
>     // and similarly for class Y, class Z, ...

>     class DataX : public X<DataX> {
>        Data data;
>        int value() const { return data.value(); }
>        friend class X<DataX>;
>     public:
>        /* ... other stuff ... */
>     };

>     class DataYZ : public Y<DataYZ>, Z<DataYZ> {
>        Data data;
>        int value() const { return data.value(); }
>        friend class Y<DataYZ>;
>        friend class Z<DataYZ>;
>     public:
>        /* ... other stuff ... */
>     };

> Comments?

> Thanks!
> Michael


>       [ about comp.lang.c++.moderated. First time posters: do this! ]


      [ about comp.lang.c++.moderated. First time posters: do this! ]