help with a 'diamond' type interface design

A

Andrew

Hi,

I try to understand the decoupled design based on interfaces but I see
that some problems arise and I have not found a place where this is
discussed.
The client code works with interface classes, decoupled from their
implementation:

class IItem
{
public:
virtual ~IItem() { }
virtual bool get_name(string& name) = 0; //
some common properties
virtual bool get_size(unsigned long &size) = 0;
}

class IAItem : public IItem
{
public:
// methods specific to IAItem
}

class IBItem : public IItem
{
public:
// methods specific to IBItem
}


// client code uses
IItem* pItem = ...
string name;
pItem->get_name(name);
usigned long size;
pItem->get_size(size);


The implementation will want to have a common abstract class derived
from IItem where these common properties are implemented:

class ItemAbstract : public IItem
{
public:
virtual bool get_name(string& name) { ... } //
some
common properties implemented
virtual bool get_size(unsigned long &size) { .... }
}

but the problem appears with the implementation of the IAItem or
IBItem:

class AItem : public IAItem, public ItemAbstract
{
public:
// implementation of IAItem
}



IItem
IAItem ItemAbstract
AItem

this implementation is ambigous because the AItem class will have 2
instances of IItem (one inherited through IAItem and one through the
ItemAbstract) so i need that:

class IAItem : virtual public IItem
class ItemAbstract : virtual public IItem

But, although this works, overseeing (for the moment) that fact that
this will give an warning saying that AItem inherits the ItemAbstract
methods through dominance, the problem i see is that at one moment I
needed to change the initial design of the interface.

Assuming the interfaces design is OK, what if I could not do that,
i.e. maybe those interfaces are from a library or something, hence
read-only for me (the implementor) ? ( i cannot change and make IAItem
derive virtually from IItem). One way would be that both AItem and
BItem derive from IAItem and IBItem respectively but this means I need
to duplicate the implementation code of IItem. To solve this I can
still have the AbstractItem and the AItem and BItem aggregate it like
this:

IItem
IAItem IBItem AbstractItem
AItem BItem


What's your opinion ?

Thanks.
 
J

James Kanze

I try to understand the decoupled design based on interfaces
but I see that some problems arise and I have not found a
place where this is discussed. The client code works with
interface classes, decoupled from their implementation:
class IItem
{
public:
virtual ~IItem() { }
virtual bool get_name(string& name) = 0; //
some common properties
virtual bool get_size(unsigned long &size) = 0;
}
class IAItem : public IItem
{
public:
// methods specific to IAItem
}
class IBItem : public IItem
{
public:
// methods specific to IBItem
}
// client code uses
IItem* pItem = ...
string name;
pItem->get_name(name);
usigned long size;
pItem->get_size(size);
The implementation will want to have a common abstract class derived
from IItem where these common properties are implemented:
class ItemAbstract : public IItem
{
public:
virtual bool get_name(string& name) { ... } //
some
common properties implemented
virtual bool get_size(unsigned long &size) { .... }
}
but the problem appears with the implementation of the IAItem or
IBItem:
class AItem : public IAItem, public ItemAbstract
{
public:
// implementation of IAItem
}

I'm not sure that you should be using a diamond here. The usual
solution is to inherit just from ItemAbstract, and be done with
it.
IItem
IAItem ItemAbstract
AItem
this implementation is ambigous because the AItem class will have 2
instances of IItem (one inherited through IAItem and one through the
ItemAbstract) so i need that:
class IAItem : virtual public IItem
class ItemAbstract : virtual public IItem

But, although this works, overseeing (for the moment) that fact that
this will give an warning saying that AItem inherits the ItemAbstract
methods through dominance,

Turn the warning off---who ever put the warning into the
compiler doesn't understand C++, or isn't familiar with its
common idioms.
the problem i see is that at one moment I
needed to change the initial design of the interface.

How?

IItem doesn't change (obviously); it's impervious to the
existence of ItemAbstract.

ItemAbstract was designed from the start to be a "partial"
implementation. So it inherits virtually from the interface;
that should be an automatism. The virtual inheritance isn't
always necessary, and if it isn't used, and the profiler says
that it has to go, there's always time for that. But most
inheritance, and all inheritance where the class can't a leaf in
the hierarchy, should be virtual.

I'm not sure where IAItem comes in at all, but if it counts on
ItemAbstract (or someone else) providing some of the functions,
it should inherit virtually as well. (The presence of IAItem
really makes the classical mixin idiom. And of course,
inheritance is always virtual in a mixin.)

Or is IAItem an extension to the interface, and not an
implementation. If so, it should inherit virtually from the
start; extensions to interfaces should normally inherit
virtually. (Unlike the rules above, this rule doesn't seem to
be widely recognized or followed---is this what you mean by the
implementation forcing a modification in the design? If so, the
answer is 1) even without ItemAbstract, IAItem should inherit
virtually, and 2) in a very real sense, whether the inheritance
is virtual or not is an implementation detail---it is
conceptually virtual from the very beginning.)

For those who don't like virtual inheritance, there is also an
interesting solution which treats the hierarchy like a template
based mixin: the interfaces derive directly (non-virtually),
e.g.:

class IItem { virtual void f() = 0 } ;
class IAItem : public IItem { virtual void g() = 0 ; } ;

The partial implementations don't derive, but rather use
duck-typing, e.g.:

class AbstractItem { void f() { ... } } ;
class AbstractAItem { void g() { ... } } ;

The concrete classes are all defined by means of a template:

template< typename ItemImpl, typename AItemImpl >
class AItem : public IAItem
{
ItemImpl myItem ;
AItemImpl myAItem ;
public:
virtual void f() { myItem.f() ; }
virtual void g() { myAItem.g() ; }
} ;

I'm not too sure what this buys you over the classical mixin,
however. Using a template for the concrete class in a template
hierarchy is generally a good idea, but if you use virtual
inheritance, with the implementation classes also figuring in
the hierarchy, you don't need any forwarding functions in the
template (except maybe for the constructors); I've had a couple
of cases in the past where the class template didn't contain a
single function, e.g.:

template< typename AImpl, typename BImpl >
class Concrete : public AImpl, public BImpl
{
} ;
Assuming the interfaces design is OK, what if I could not do that,
i.e. maybe those interfaces are from a library or something, hence
read-only for me (the implementor) ?

Then you need some sort of forwarding scheme, as above.

You also should post an error report to where ever the library
originated. Not using virtual inheritance in such cases is an
error, pure and simple.
( i cannot change and make IAItem
derive virtually from IItem). One way would be that both AItem and
BItem derive from IAItem and IBItem respectively but this means I need
to duplicate the implementation code of IItem. To solve this I can
still have the AbstractItem and the AItem and BItem aggregate it like
this:
IItem
IAItem IBItem AbstractItem
AItem BItem
What's your opinion ?

That if there's a problèm, there's a design error in the library
to begin with, since in such cases virtual inheritance is (or
should be) the rule. Regretfully... I've encountered the
problem a couple of times myself---I've always been able work
around it using something like the class template above.
 

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

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,744
Latest member
CortneyMcK

Latest Threads

Top