假设Domain
存储指向Shape
的指针。确切的形状(Triangle
或Rectangle
)在编译时是未知的,并且在读取输入后将会清楚。在运行时,我可能需要访问派生结构的变量,但这是不可能的,因为指针指向基础结构。我找到了另一个解决方案,即"开启类型"但正如答案here中所指出的那样,这是令人沮丧的。他还说过
当你使用多态时,你不应该关心基类引用/指针背后的内容。
在这种情况下,我确实关心所以听起来我不应该使用多态。我想我在下面做的是一个糟糕的设计,但那么解决这个问题的好设计是什么?
struct Shape
{
int common_variable;
};
struct Triangle: Shape
{
int triangle_specific_variable;
};
struct Rectangle: Shape
{
int rectangle_specific_variable;
};
struct Domain
{
Shape* shape;
};
int main()
{
Domain domain;
//domain.shape = new Triangle(); // depends on input.
//domain.shape = new Rectangle(); // depends on input.
return 0;
}
答案 0 :(得分:6)
你的问题清楚地表明需要多态性,因为你想使用三角形,重新排列等等,你知道所有这些都是形状。
为什么不建议使用交换机访问特定数据?
因为这与多态设计完全相反。而不是使用形状,绘制它们,计算它们的面积等...你总是需要知道形状的类型和代码特定的行为。
想象一下,你已经完成了你的代码,然后你发现你也想要正方形和圆形:维持这个是多么噩梦。
如何解决这个问题?
您必须从具体类中抽象出来,并定义可以对常规形状执行的一般操作。然后将这些操作定义为虚函数,并在使用Domain的代码中,只需调用虚函数。
要进一步进行分类,您可以使用从流中返回形状的工厂方法,而不是从类中创建对象。
示例:
class Shape
{
public:
virtual void scale(double scale_factor)=0;
virtual void rotate(double angle)=0;
virtual void draw(window w)=0;
virtual Shape* clone()=0;
virtual ~Shape() {}
};
class Triangle: public Shape
{
Point A, B, C;
public:
Triangle (Point a,Point b, Point c) : A(a), B(b), C(c) { }
void scale(double scale_factor) override;
void rotate(double angle) override;
void draw(window w) override;
Shape* clone() { return new Triangle(*this); }
};
...
int main()
{
Domain domain, domain2;
Window wnd = CreateWindow(...); // depends on your GUI library
Point a,b,c;
cin >> a >> b >> c;
domain.shape = new Triangle(a,b,c);
// Once the object is constructed no need to know the details of the shape here
domain.shape->rotate(45);
domain2.shape = domain.shape->clone();
domain.shape->draw(wnd);
...
return 0;
}
请注意,使用智能指针比使用原始指针更安全;
答案 1 :(得分:0)
首先。当具体对象具有完全相同的界面时,多态性几乎总是只是工作的正确工具。
其次,情况很少,有时多态性比变体更适合。
在这种情况下,我们将行为推迟到实现,而不是试图从对象外部推断出它。
这样做的一种方法是访问者模式':
struct triangly_thing { int i; };
struct rectangly_thing { int i; };
struct shape_visitor
{
virtual void operator()(triangly_thing thing) const
{
// do triangly things
}
virtual void operator()(rectangly_thing thing) const
{
// do rectangly things
}
};
struct Shape
{
int common_variable;
virtual void visit(shape_visitor const& visitor)
{
}
};
struct Triangle: Shape
{
triangly_thing my_triangly_thing;
void visit(shape_visitor const& visitor) override
{
visitor(my_triangly_thing);
}
};
struct Rectangle: Shape
{
rectangly_thing my_rectangly_thing;
void visit(shape_visitor const& visitor) override
{
visitor(my_rectangly_thing);
}
};
struct Domain
{
Shape* shape;
};
int main()
{
Domain domain;
struct my_shape_visitor_type : shape_visitor
{
// customise overrides in here
} my_shape_visitor;
domain.shape->visit(my_shape_visitor);
return 0;
}