为了变形或填充,这是个问题! (C ++)

时间:2011-07-20 11:39:06

标签: c++ polymorphism encapsulation

我需要将一个多态对象(比方说Polygon)存储在另一个对象中(比方说Simulation)。同时我想保留Simulation的封装。

class Polygon {
public:
  virtual double area() { return 0; }
};

class Square : public Polygon {
public:
  Square(double edge) : edge_(edge) {}
  virtual double area() { return edge_*edge_; }
private:
  double edge_;
};

class Simulation {
public:
  Simulation(Polygon& polygon) { polygon_ = &polygon; }
  Polygon* polygon() { return polygon_; }
private:
  Polygon* polygon_;
};

int main (int argc, const char * argv[]) {
  Square square(2.0);
  Simulation sim(square);
  std::cout<<sim.polygon()->area()<<"\n";
  return 0;
}

这完全没问题!但是,它违反了Simulation的封装,事实上,如果从我main开始更改square,它也会在Simulation内更改。

我正在考虑使用复制构造函数修改Simulation的构造函数:

Simulation(Polygon& polygon) { polygon_ = new Polygon(polygon); }

但这意味着我没有多态性......

这里显然有一些我想念的东西...... CHEERS!

6 个答案:

答案 0 :(得分:3)

向Polygon(和虚拟析构函数!)添加克隆函数。确保Polygon是抽象的是一个好主意,所以要确保至少有一个函数是纯虚拟的。

您的Simulation类需要复制构造函数,析构函数和赋值运算符。 请注意,Square克隆函数可以返回Square *,即使超类返回Polygon *,因为它是协变的。一些较旧的编译器可能不支持这种情况,在这种情况下返回一个Polygon *。

class Polygon {
public:
  virtual ~Polygon() = 0;
  virtual Polygon* clone() const = 0;
  virtual double area() { return 0; }
};
inline Polygon::~Polygon() {}

class Square : public Polygon {
public:
  Square(double edge) : edge_(edge) {}
  virtual Square* clone() const { return new Square(*this); }
  virtual double area() { return edge_*edge_; }
private:
  double edge_;
};

class Simulation {
public:
  Simulation(Polygon const& polygon) 
  : polygon_(polygon.clone())
  {}
  Simulation(Simulation const& rhs) 
  : polygon_(rhs.polygon_->clone())
  {}
  Simulation& operator=(Simulation const& rhs) 
  {
      if (this != &rhs) {
          delete polygon_;
          polygon_ = rhs.polygon_->clone();
      }
      return *this;
  }
  ~Simulation() {
     delete polygon_;
  }
  Polygon* polygon() { return polygon_; }
private:
  Polygon* polygon_;
};

答案 1 :(得分:1)

如果Simulation包含Polygon,则表示它意味着要对其执行某些操作。如果您需要直接从“外部”访问多边形,您可能在某处错过了设计,或者如果没有,您可以使用观察者模式并让多边形通知模拟,如果它发生变化。

所以,要么:

outside -> polygon -> callback -> simulation 

outside -> simulation -> polygon

答案 2 :(得分:1)

所以你要确保外部代码无法改变模拟的内部多边形,但是允许在其中使用任何子类?即确保模拟之外没有引用参考文件中的ref传递的对象?

您可以想到一个抽象的复制方法来实现:(不要忘记模拟析构函数中的delete

class Polygon {
public:
   virtual Polygon *copy() = 0;
   //..
};
class Square : public Polygon {
public:
   virtual Polygon *copy() { return new Square(_edge); }
   //...
}
class Simulation {
public:
   Simulation(const Polygon &p) : poly(p.copy()) {}
};

答案 3 :(得分:0)

您只需确定多边形是在模拟内部还是外部。如果它应该在它之外,那么你有引用构造函数参数。如果它在里面,你需要以下代码:

class Simulation {
public:
    Simulation() : poly(2.0) { }
    Polygon *polygon() { return &poly; }
private:
    Square poly;
};

现在,您可以轻松地执行多态方面:

class Simulation {
public:
    Simulation() : poly(2.0), poly2(3.0) { }
    Polygon *polygon(int i) 
   { 
       switch(i) { 
          case 0: return &poly;  
          case 1: return &poly2; 
       } 
       return 0; 
   }
private:
    Square poly;
    Cylinder poly2;
};

一旦你厌倦了添加新的数据成员,这是另一个解决一些案例的技巧:

class Simulation {
public:
    Simulation() : poly(2.0) { }
    Polygon *polygon(float x) 
    {
        poly.edge_ = x;
        return &poly;
    }
private:
    Square poly;
 };

编辑:请注意,需要仔细考虑头文件中类的顺序。

答案 4 :(得分:0)

如果要复制多态对象,可以使用克隆方法完成此操作。

class Polygon
{
  ...
  virtual Polygon* clone() const = 0;
};

class Square: public Polygon
{
  ...
  virtual Square* clone() const { return new Square(*this); }
};

然而,在这个例子中,仿真似乎没有意义,仿真既不对多边形本身做任何事情,也不想把它交给其他代码使用。

答案 5 :(得分:0)

这就是C ++的工作原理。如果为对象(PIMPL)编写包装器,则必须实现其完整接口。只需将调用传递给实际的实现,函数就会非常小,但你必须编写它们。然后你可以改变行为,添加记录或任何你需要的东西......