One approach would be to make stuff more general in order to avoid casting to specific types.
You could implement a basic getter/setter of "dimension" float properties in the base class, which sets a value in a map, based on a a specific key for the property name. Example below:
class AbstractShape
{
public :
typedef enum{
SQUARE = 0,
CIRCLE,
} SHAPE_TYPE;
AbstractShape(SHAPE_TYPE type):m_type(type){}
virtual ~AbstractShape();
virtual float computePerimeter() const = 0;
void setDimension(const std::string& name, float v){ m_dimensions[name] = v; }
float getDimension() const{ return m_dimensions[name]; }
SHAPE_TYPE getType() const{return m_type;}
protected :
const SHAPE_TYPE m_type;
std::map<std::string, float> m_dimensions;
};
Then, in your manager class you need to implement only one function, like below:
void ShapeManager::changeShapeDimension(const int shapeIndex, const std::string& dimension, float value){
m_shapes[shapeIndex]->setDimension(name, value);
}
Example of usage within the View:
ShapeManager shapeManager;
shapeManager.addShape(new Circle());
shapeManager.changeShapeDimension(0, "RADIUS", 5.678f);
float circlePerimeter = shapeManager.computeShapePerimeter(0);
shapeManager.addShape(new Square());
shapeManager.changeShapeDimension(1, "WIDTH", 2.345f);
float squarePerimeter = shapeManager.computeShapePerimeter(1);
Another suggestion:
Since your manager only exposes the setter and the perimeter computation (which are exposed by Shape as well), you could simply instantiate a proper View when you instantiate a specific Shape class. EG:
- Instantiate a Square and a SquareEditView;
- Pass the Square instance to the SquareEditView object;
- (optional) Instead of having a ShapeManager, in your main view you could still keep a list of Shapes;
- Within SquareEditView, you keep a reference to a Square; this would eliminate the need of casting for editing the objects.