C++中的多重继承导致难以覆盖常见功能

4 c++ inheritance class

在C++物理模拟中,我有一个名为Circle和Square的类.这些是形状,并有一个名为push()的方法,它对它施加力.然后是Circle的一个特例,称之为SpecialCircle,其中push()应该表现出略微不同的属性.但事实上,还有SpecialSquare()应该具有相同的力属性.所以我想要一个名为Shape的抽象基类来处理Circles和Squares,但是我还想要一个名为Special的抽象基类,它将特殊属性应用于force().

设计这种类结构的最佳方法是什么?

到目前为止,我有:

class Shape {
    virtual void push();
};

class Circle : public Shape {};

class Square : public Shape {};

class Special {
    virtual void push();
};

class SpecialCircle : public Circle, Special {};

class SpecialSquare : public Square, Special {};
Run Code Online (Sandbox Code Playgroud)

当然,上面不会编译,因为Special :: push()和Shape :: push()冲突.正如预期的那样,我得到"错误:请求成员'推送'是模棱两可的".

如何重新组织我的类结构,以便Circle和Square可以相互共享某些属性,但是SpecialCircle和SpecialSquare仍然可以继承Shape,还可以继承Special的修改功能?

谢谢.

ps.,这是钻石继承问题吗?

Fed*_*oni 9

另一种解决方案(它可能适合您的需求,也可能不适合您的需求,具体取决于您的实施细节):

  • 拥有类Behavior,让NormalBehavior和SpecialBehavior继承它.
  • 让类成为Shape,让Square和Circle继承它.让Shape成为聚合类型,使用Behavior成员(即将Behavior对象传递给各种Shape构造函数).换句话说,让一个Shape有一个行为.
  • 将形状行为的实际差异委托给行为层次结构的方法.

相反,您可以:

  • 拥有PhysicalObject类,让NormalObject和SpecialObject继承它;
  • 让班级变形,让Square和Circle继承它;
  • 让PhysicalObject具有Shape.

更喜欢继承聚合.这是Bridge模式的应用.这个策略相对于Square,SpecialSquare,Circle和SpecialCircle的优势在于明天你必须添加Rectangle,Hexagon等等,对于你添加的每个形状,你必须实现两个类(重复)代码是邪恶的); 在我看来,这是Bridge解决的真正问题.


Mic*_*urr 5

据说软件中的每个问题都可以通过添加额外的间接层来解决。

Herb Sutter 有一篇关于如何解决问题的优秀文章:多重继承 - 第三部分

简而言之,您使用中间类来“重命名”虚拟函数。正如赫伯所说:

重命名虚拟功能

如果两个继承的函数具有不同的签名,则不会有问题:我们只需像往常一样独立地重写它们即可。那么,诀窍就是以某种方式更改两个继承函数中至少一个的签名。

更改基类函数签名的方法是创建一个从基类派生的中间类,声明一个新的虚函数,并覆盖继承的版本以调用新函数

这是一个使用您的类的长示例:

class Shape {
public:
    virtual void push() = 0;
};

class Circle : public Shape 
{
public:
    void push() {
        printf( "Circle::push()\n");
    }
};

class Square : public Shape 
{
public:
    void push() {
        printf( "Square::push()\n");
    }
};

class Special {
public:
    virtual void push() = 0;
};


class Circle2: public Circle
{
public:
    virtual void pushCircle() = 0;
    void push() {
        pushCircle();
    }
};

class Square2: public Square
{
public:
    virtual void pushSquare() = 0;
    void push() {
        pushSquare();
    }
};


class Special2 : public Special
{
public:
    virtual void pushSpecial() = 0;
    void push() {
        pushSpecial();
    }
};



class SpecialCircle : public Circle2, public Special2 
{
public:
    void pushSpecial() {
        printf( "SpecialCircle::pushSpecial()\n");
    }
    void pushCircle() {
        printf( "SpecialCircle::pushCircle()\n");
    }

};

class SpecialSquare : public Square2, public Special2 
{
public:
    void pushSpecial() {
        printf( "SpecialSquare::pushSpecial()\n");
    }
    void pushSquare() {
        printf( "SpecialSquare::pushSquare()\n");
    }

};

int main( int argc, char* argv[])
{
    SpecialCircle sc;
    SpecialSquare ss;

    // sc.push();   // can't be called - ambiguous
    // ss.push();
    sc.pushCircle();
    ss.pushSquare();

    Circle* pCircle = ≻
    pCircle->push();

    Square* pSquare = &ss;
    pSquare->push();

    Special* pSpecial = ≻
    pSpecial->push();

    pSpecial = &ss;
    pSpecial->push();


    return 0;
}
Run Code Online (Sandbox Code Playgroud)