Interface Inheritance

An interface definition can declare zero or more base interfaces. For example


$interface IShape
{
    float64 GetArea() const;
    float64 GetPerim() const;
};

$interface IColouredShape : IShape
{
    int32 GetColour() const;
};

$interface ICircle : IShape
{
    float64 GetRadius() const;
};

$interface IColouredCircle : IColouredShape, ICircle
{
};

This allows us to speak of the subinterfaces and superinterfaces of a given interface. The interfaces form a directed acyclic graph according to the subinterface relation.

Coloured circle hierarchy

Now consider the following struct in straight C++


class ColouredCircle
{
public:
    ColouredCircle() : r(3.0), c(17) {}
    float64 GetArea() const {return 3.14*r*r;}
    float64 GetPerim() const {return 2*3.14*r;}
    float64 GetRadius() const {return r;}
    int32 GetColour() const {return c;}
private:
    float64 r;
    int32 c;
};

This can be coerced into an IColouredCircle as follows


ColouredCircle c;
ptr<IColouredCircle> p = &c;

The pointer p can be implicit upcast to a ptr<IShape>, ptr<IColouredShape> or ptr<ICircle>.

Let a subinterface refer to either a directly or indirectly inherited interface. For example, the subinterfaces of IColouredCircle are IShape, IColouredShape, ICircle.

An interface inherits all the methods from its subinterfaces. A pointer to an interface can be implicit upcast to a pointer to any subinterface.

Sideways or downwards casting of interface pointers requires a qicast<> but is only supported for interfaces that inherit from IObject (this is described below).

Repeated inheritance is supported, but only indirectly. The following is not permitted


$interface Ix {};
$interface Iy : Ix, Ix {} // compiler error

Coloured circle using subclassing

For the purpose of comparison, consider the following code using subclassing, where it has been assumed that virtual inheritance should always be used for interface inheritance:


struct IShape
{
    virtual float64 GetArea() const = 0;
    virtual float64 GetPerim() const = 0;
};

struct IColouredShape : public virtual IShape
{
    virtual int32 GetColour() const = 0;
};

struct ICircle : public virtual IShape
{
    virtual float64 GetRadius() const = 0;
};

struct IColouredCircle : public virtual IColouredShape, public virtual ICircle
{
};

class ColouredCircle : public IColouredCircle
{
public:
    ColouredCircle() : r(3.0), c(17) {}
    float64 GetArea() const {return 3.14*r*r;}
    float64 GetPerim() const {return 2*3.14*r;}
    float64 GetRadius() const {return r;}
    int32 GetColour() const {return c;}
private:
    float64 r;
    int32 c;
};

For the Microsoft Visual C++ compiler (VC 2008), the size of ColouredCircle is 56 bytes. That is an enormous overhead considering the member variables only take up 12 bytes.