How to solve this gracefully?

A

Alex

Hi, I have a problem involving some design issue.
I have two unrelated (that is, they do not derive from the same base)
classes:
ClassA
ClassB

Both have a quite similar interface, so they can be use interchangeably,
that is:

ptr = new ClassA;
ptr->f1();
ptr->f2();

To replace it with ClassB, all I need is changing the first line:

ptr = new ClassB;
ptr->f1();
ptr->f2();

(As I mentioned before, almost all the interface is identical)

This is OK when doing by hand. But I want to provide an option so a user can
toggle between both classes.
Problem is that as both classes are unrelated, I can't use a base pointer to
make instantiation..
So the most simple way I found is creating a proxy-like class, which
determines and forces the interface to be used:

class Iface {
public:
void f1();
void f2();
};

So doing:
class NewA : public ClassA, public Iface {
public:
void f1() { ClassA::f1(); }
void f2() { ClassA::f2(); }
};

and similarly
class NewB : public ClassB, public Iface {
public:
void f1() { ClassB::f1(); }
void f2() { ClassB::f2(); }
};

the I'm able to code:

Iface* ptr = new NewA;
or
Iface* ptr = new NewB;

and use them interchangeably.

Problem is -as you might have noticed- that the code to define the classes
is repetitive..

Is there a better way to solve this, and make it more elegant?

Note that in the future, I'll use ClassC with a not so similar interface. So
I find in this case the solution to be OK,
but in this specific case, maybe there's a shorter way?

Thanks.
 
H

Heinz Ozwirk

Alex said:
Hi, I have a problem involving some design issue.
I have two unrelated (that is, they do not derive from the same base)
classes:
ClassA
ClassB

Both have a quite similar interface, so they can be use interchangeably,
that is:

ptr = new ClassA;
ptr->f1();
ptr->f2();

To replace it with ClassB, all I need is changing the first line:

ptr = new ClassB;
ptr->f1();
ptr->f2();

(As I mentioned before, almost all the interface is identical)

This is OK when doing by hand. But I want to provide an option so a user
can toggle between both classes.
Problem is that as both classes are unrelated, I can't use a base pointer
to make instantiation..
So the most simple way I found is creating a proxy-like class, which
determines and forces the interface to be used:

class Iface {
public:
void f1();
void f2();
};

All member functions of the interface should be virtual (and probably pure).
You should also add a virtual d'tor.
So doing:
class NewA : public ClassA, public Iface {
public:
void f1() { ClassA::f1(); }
void f2() { ClassA::f2(); }
};

and similarly
class NewB : public ClassB, public Iface {
public:
void f1() { ClassB::f1(); }
void f2() { ClassB::f2(); }
};

You can use templates to save those repetitions:

template <class Z>
class NewZ: public Z, public Iface
{
public:
void f1() { Z::f1(); }
void f2() { Z::f2(); }
};

typedef NewZ<A> NewA;
typedef NewZ<B> NewB;

HTH
Heinz
 
A

Alex

This is OK when doing by hand. But I want to provide an option so a user
All member functions of the interface should be virtual (and probably
pure). You should also add a virtual d'tor.

Yeah, you're right!
You can use templates to save those repetitions:

template <class Z>
class NewZ: public Z, public Iface
{
public:
void f1() { Z::f1(); }
void f2() { Z::f2(); }
};

typedef NewZ<A> NewA;
typedef NewZ<B> NewB;

This is great, thanks. So the method I use seems to be the best way to solve
this?
Can this be considered like a proxy pattern approach?
 
H

Heinz Ozwirk

This is great, thanks. So the method I use seems to be the best way to
solve this?

I would never call a method to do something "the best one". There is always
the possibility, that someone comes up with a better solution. There are
only good solutions and bad solutions, and as far as I understood the
problem you wanted to solve, I wouldn't call your solution a bad one. Your
first approach had the problem that you had to manually create many wrappers
for all your types, but that has been simlyfied using a template and letting
the compiler to do the dirty work.

HTH
Heinz
 

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,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top