在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.,这是钻石继承问题吗?
另一种解决方案(它可能适合您的需求,也可能不适合您的需求,具体取决于您的实施细节):
相反,您可以:
更喜欢继承聚合.这是Bridge模式的应用.这个策略相对于Square,SpecialSquare,Circle和SpecialCircle的优势在于明天你必须添加Rectangle,Hexagon等等,对于你添加的每个形状,你必须实现两个类(重复)代码是邪恶的); 在我看来,这是Bridge解决的真正问题.
据说软件中的每个问题都可以通过添加额外的间接层来解决。
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)
| 归档时间: |
|
| 查看次数: |
5182 次 |
| 最近记录: |