Parallel inheritance between interface classes and implementation classes in C ++

I am trying to use the C ++ abstract base class in the same way as with the Java interface. Suppose we have the following interface classes with only pure virtual functions:

class Shape { virtual double area()=0; };
class Square : public Shape { virtual void setLength(double length)=0; };
class Rectangle : public Square { virtual void setWidth(double width)=0; };

and I'm trying to implement Square and Rectangle as follows:

class SquareImpl : public Square { /*implementation*/ };
class RectangleImpl : public SquareImpl, Rectangle { /*implementation*/ };

Where RectangleImplheritage as SquareImplwell as Rectanglefor re-use, say SquareImpl::area(). However, when I try to compile, two problems arise: firstly, all methods in are SquareImplnot inherited properly, and I have to manually override RectangleImpl::area()and RectangleImpl::setLength(). Secondly, it still introduces the diamond problem, which Shapeis an ambiguous basis RectangleImpl.

I could compile the code if I actually inherited Squarefrom Shape, but I don’t think that the performance will scale with the addition of additional derived interfaces. It is also strange that RectangleImplit still does not inherit SquareImpl::setLength(), although it is SquareImpl::area()inherited well. (ignore practicality here)

Another solution may be to make the interfaces independent of each other, i.e. do Squarenot inherited from Shape. But in doing so, I will lose access to methods in Shapeif I define functions that take a pointer Square*. This will also make static_cast between Shapeand impossible Square.

, : - ++ , ?

( : - . , , , .)

+5
6

Diamond, OO, . , , , Java .

++ - .

, codymanix, - , OO .

. -, , , - , " ". -, class Square class SquareImpl. , Square, , , , . , Square SquareImpl .

, , ++, Java, . Java . ++ , .

+3

, . . A , .

+2

, . , , , . :

class Square : public Shape {...};
class Rectangle : public Shape {...};

, Square::setSide(double) Rectangle::setLengthAndWidth(double, double). * Impl. .

0

, , - - .. , , .

, , - ( , , v-). , setLength - , , .

0

: Rectangle- > Square- > Shape SquareImpl, .

- , . RectangleImpl Square Rectangle. SquareImpl RectangleImpl , , , - .

0

sean, , ++, .

, , . Ball, , FooBall, Foo, FooBarBall, FooBall, , Foo . , , FooBall, , Bar. , .

, , Foo Bar Ball, FooBall, Foo toFoo(). , Foo Bar .

, , Foos . - Ball, FooBall FooBarBall, . Foo Bar, -. , , Foo Bar.

#include <stdio.h>

class Ball {
  public:
    // All balls can roll.
    virtual void roll() = 0;

    // Ball has many other methods that are not
    // covered here.

    virtual inline ~Ball() {
        printf("deleting Ball\n");
    };
};

class Foo {
  public:
    virtual void doFoo() = 0;

    // do some very complicated stuff.
    virtual void complexFoo() = 0;

    virtual inline ~Foo() {};
};

/** 
 * We assume that classes that implement Bar also
 * implement the Foo interface. The Bar interface
 * specification failed to enforce this constraint
 * by inheriting from Foo because it will introduce
 * diamond inheritance into the implementation.
 **/
class Bar {
  public:
    virtual void doBar() = 0;
    virtual void complicatedBar() = 0;

    virtual inline ~Bar() {};
};

class FooBall : public Ball {
  public:
    virtual Foo* toFoo() = 0;

    virtual inline ~FooBall() {};
};

/**
 * A BarBall is always also a FooBall and support
 * both Foo and Bar methods.
 **/
class FooBarBall : public FooBall {
  public:
    virtual Bar* toBar() = 0;

    virtual inline ~FooBarBall() {};
};


/* Composite Implementation */

class FooImpl_A : public Foo {
  public:
    virtual void doFoo() {
        printf("FooImpl_A::doFoo()\n");
    };

    virtual void complexFoo() {
        printf("FooImpl_A::complexFoo()\n");
    }

    virtual inline ~FooImpl_A() {
        printf("deleting FooImpl_A\n");
    }
};

class FooBarImpl_A : public FooImpl_A, public Bar {
  public:
    virtual void doBar() {
        printf("BarImpl_A::doBar()\n");
    }

    virtual void complicatedBar() {;
        printf("BarImpl_A::complicatedBar()\n");
    }

    virtual inline ~FooBarImpl_A() {
        printf("deleting FooBarImpl_A\n");
    }
};

/* Composite Pattern */
class FooBarBallContainer : public FooBarBall {
  public:

    /* FooBarBallImpl_A can take any class that
     * implements both the Foo and Bar interface, 
     * including classes that inherit FooBarImpl_A
     * and other different implementations.
     *
     * We'll assume that realFoo and realBar are
     * actually the same object as Foo methods have
     * side effect on Bar methods. If they are not
     * the same object, a third argument with false
     * value need to be supplied.
     */
    FooBarBallContainer( Foo* realFoo, Bar* realBar, bool sameObject=true ) : 
    _realFoo(realFoo), _realBar(realBar), _sameObject(sameObject) {}

    virtual void roll() {
        // roll makes use of FooBar methods
        _realBar->doBar();
        _realFoo->complexFoo();
    }

    virtual Foo* toFoo() {
        return _realFoo;
    }

    virtual Bar* toBar() {
        return _realBar;
    }

    virtual ~FooBarBallContainer() {
        delete _realFoo;

        // Check if realFoo and realBar are
        // not the same object to avoid deleting
        // it twice.
        if(!_sameObject) {
            delete _realBar;
        }
    }

  private:
    Foo* _realFoo;
    Bar* _realBar;
    bool _sameObject;
};


/* Monolithic Implmentation */

class FooBarBallImpl_B : public FooBarBall,
    public Foo, public Bar {

  public:
    virtual void roll() {
        complicatedBar();
        doFoo();
    }

    virtual Foo* toFoo() {
        return (Foo*) this;
    }

    virtual Bar* toBar() {
        return (Bar*) this;
    }

    virtual void doFoo() {
        printf("FooBarBallImpl_B::doFoo()\n");
    }

    virtual void complexFoo() {
        printf("FooBarBallImpl_B::complexFoo()\n");
    }

    virtual void doBar() {
        printf("FooBarBallImpl_B::doBar()\n");
    }

    virtual void complicatedBar() {
        printf("FooBarBallImpl_B::complicatedBar()\n");
    }

};

/* Example usage of FooBarBall */
void processFooBarBall(FooBarBall *ball) {

    Foo *foo = ball->toFoo();
    foo->doFoo();

    ball->roll();

    Bar *bar = ball->toBar();
    bar->complicatedBar();
}

main() {

    FooBarImpl_A *fooBar = new FooBarImpl_A();
    FooBarBall *container = new FooBarBallContainer(fooBar, fooBar);

    printf
    processFooBarBall(container);
    delete container;

    FooBarBallImpl_B *ball = new FooBarBallImpl_B();
    processFooBarBall(ball);

    // we can even wrap FooBarBallImpl_B into the container
    // but the behavior of roll() will become different
    container = new FooBarBallContainer(ball, ball);
    processFooBarBall(container);

    delete container;

}
0
source

All Articles