2016-08-23 123 views
1

假设一个Domain存储一个指向Shape的指针。确切的形状(TriangleRectangle)在编译时并不知道,并且在读取输入后会清楚。在运行时,我可能需要访问派生结构的变量,但这是不可能的,因为指针指向基础结构。我发现另一种解决方案是“开启型”,但如答案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

我不太明白你的问题或你的榜样。看起来这里有一个多态的方法可能是有用的,但是我不太了解你想要做什么来帮助。 – callyalater

+0

@callyalater:我需要访问派生结构特定的变量,但我不能因为指针指向基础结构。 – Shibli

+0

如果你想通过'Base'指针访问'Derived'结构的成员,你可以使用'dynamic_cast',但是你需要创建'Base'类的多态类,例如虚拟的'virtual void f(){ }'功能。 – PcAF

回答

6

你的问题清楚地表明需要多态,只要你想用三角形,rechtangles等工作,你知道,所有这些都是形状。

为什么不建议使用交换机访问特定数据?

因为这与多态设计完全相反。而不是使用形状,绘制它们,计算面积等......您总是需要知道形状的类型并编写特定的行为。想象一下,你已经完成了你的代码,然后你发现你也想要正方形和圆圈:维护这个是多么的噩梦。

如何解决这个问题?

您必须从具体类中抽象出来,并定义可以在常规形状上执行的常规操作。然后将这些操作定义为虚函数,并在您的代码中使用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; 
} 

注意,与智能指针工作会比原始指针更安全;

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; 
}