我需要将一个多态对象(比方说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!
答案 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)编写包装器,则必须实现其完整接口。只需将调用传递给实际的实现,函数就会非常小,但你必须编写它们。然后你可以改变行为,添加记录或任何你需要的东西......