class AbstractShape;
class RectangularShape : public AbstractShape
{
void setWidth(double v);
void setLength(double v);
};
class CircleShape : public AbstractShape
{
void setRadius(double v);
};
class PolygonalShape : public AbstractShape
{
void addPoint(Point p);
};
class Element
{
protected:
AbstractShape* _shape; //RectangularShape, PolygonalShape or CircleShape
};
I want to create methods in Element to modify the shape _shape of Element ( ie if the shape is Rectangular I have to be able to change the length and the width, otherwise I have to be able to add a Point to the polygonal shape etc ).
For instance I cannot declare a setLength method because setLength as only a meaning if _shape is a RectangularShape. A solution would be to subclass Element in RectangularElement, PolygonalElement, CircularElement but I would like to avoid this solution.
Do you see another way to do that ?
May be you could do something like following :
class Shape
{
// ....
virtual void setWidth(double v) { /* not implemented, throw error ? */ }
virtual void setLength(double v){ /* not implemented, throw error ? */}
virtual void setRadius(double v){ /* not implemented, throw error ? */}
virtual void addPoint(Point p) { /* not implemented, throw error ? */}
//....
};
class RectangularShape : public Shape
{
void setWidth(double v) override ;
void setLength(double v) override;
};
class CircleShape : public Shape
{
void setRadius(double v) override ;
};
class PolygonalShape : public Shape
{
void addPoint(Point p) override;
};
class Element
{
protected:
Shape* _shape; //Any shape
};
Calling meaningless function on a _shape will print a message or assert .
Other than basic fat interface implementation I mentioned, if you don't want to pollute your abstract base class for whatever reason, one possible solution is to use a fat interface on another class and capability queries
class AbstractShape {};
class RectangularShape : public AbstractShape
{
public:
void setWidth(double v);
void setLength(double v);
};
class CircleShape : public AbstractShape
{
public:
void setRadius(double v);
};
class PolygonalShape : public AbstractShape
{
public:
void addPoint(Point p);
};
class Element {
public:
void setWidth(double);
void setLength(double);
void setRadius(double);
void addPoint(Point);
protected:
std::unique_ptr<AbstractShape> shape;
};
And the implementation of setWidth() for example could look like this
void Element::setWidth(double val) {
if (auto rectangle = dynamic_cast<Rectangle*>(this->shape.get())) {
rectangle->setWidth(val);
} else {
throw std::runtime_error{"This type does not implement setWidth()"};
}
}
Also note that you probably want to use a std::unique_ptr and not a raw pointer.
Related
I'm making a simple MVC example for c++ classes at my uni. First, look at the code:
The executor.h part:
class IExecutor {
IParams params;
public:
virtual void initialize(IParams iParams);
virtual void execute();
};
class QEExec : public IExecutor {
public:
void initialize(QEParams iParams) override;
void execute() override;
};
And now params.h part:
class IParams {
};
class QEParams : public IParams {
public:
int a;
int b;
int c;
};
The problem is that I want to create void initialize(QEParams iParams) function for QEExec and pass QEParams to it in order to have access to a, b, and c parameters (I'll need that later) but I can't do so because of virtual void initialize(IParams). I thought that if QEParams is derives from IParams I will be able to do so, but I can't access parameters that I mentioned earlier. How to make it work so that I'll be able to access a, b and c parameters in initialize function?
EDIT: I'll put a photo of how it should look like:
https://i.stack.imgur.com/KWaSQ.jpg
Interface doesn't have any fields
Interface has only pure virtual methods
Name initialize of IExecutor indicates some misunderstanding. Looks like it suppose to be called once at the begging during construction time. It should be hidden in step where some factory creates object implementing IExecutor
So basically I'm suspecting you need more something like this:
class IExecutor
{
public:
virutal ~IExecutor() {}
virtual void execute() = 0;
};
struct QEParams {
int a;
int b;
int c;
};
class QEExec: public IExecutor
{
public:
QEExec(int b, int c) ....
void initialie(); // second step init
void execute() override;
};
class CAExec: public SomeOtherBaseClass, public IExecutor
{
public:
CAExec(int a, int c) ....
void execute() override;
};
std::unique_ptr<IExecutor> executorFactory(const QEParams& params)
{
if (params.a < 0) {
auto result = std::make_unique<QEExec>(params.b, params.c);
result->initialie();
return result;
}
return std::make_unique<CAExec>(params.a, params.c);
}
Usually factory parameters are structural data and extra abstraction is obsolete.
If different kind of arguments are needed to create alternative version of IExecutor you just provide different factory function (possibly overload):
std::unique_ptr<IExecutor> executorFactory(const std::string& fileName)
{
....
}
It sounds like you're using OOP incorrectly.
Since QEExec is a IExecutor (it inherits), and it can initialize just like IExecutor can, ideally, both of those initialize's will be doing similar things to their IParams objects. If so, then the one who should be acting on a, b and c should be QEParams, not QEExec.
You could do this with polymorphism like:
class IParams {
virtual void init_logic() { }
};
class QEParams : public IParams {
public:
void init_logic() { /* Do something with a/b/c */ }
private:
int a;
int b;
int c;
};
And then...
class IExecutor {
IParams params;
public:
virtual void initialize(IParams *iParams);
virtual void execute();
};
class QEExec : public IExecutor {
public:
//Will call the QEParams init_logic when passed a QEParams pointer
void initialize(IParams *iParams) { iParams->init_logic(); }
void execute() override;
};
I have two classes:
class My_package, which have methods that are just for sending stuff to the hardware and class Automation_algorithm, that perform all the algorithm that process my data.
So what I thought I should do is to have an instance of class Automation_algorithm as a member of my class My_package.
But at some point, I execute a method from the class Automation_algorithm, and in this method, I check if a certain condition is met, and if it is met, I would like to use a method from the class My_package to send an acceleration command to my system. But how do I call a method accelerate() from the "containing class".
For clarity, I have something like
class My_package
{
public :
void accelerate(double a,double t);
...
private:
Automation_algorithm my_algorithm;
...
};
class Automation_algorithm
{
public:
void method1(); // I want to call accelerate(a,t) from here!!!
...
private:
...
};
I thank you for your responses and taking in consideration that I am not a c++ champ.
Using Bridge Design Pattern, here's a snippet:
class My_package
{
public:
My_package();
void accelerate(double a, double t);
struct impl; // declaring the implementation
private:
Automation_algorithm my_algorithm;
std::unique_ptr<impl> impl_; // implementation is defined here
};
struct My_package::impl {
impl() {}
void accelerate(double a, double t) {/* */} // implementation is defined here
};
My_package::My_package() : impl_( new impl() ) {}
void My_package::accelerate(double a, double t) { impl_->accelerate(a, t); }
class Automation_algorithm
{
public:
Automation_algorithm();
void method1(void)
{
double a,t;
impl_->accelerate(a, t);
}
private:
std::unique_ptr<struct My_package::impl> impl_;
};
Automation_algorithm::Automation_algorithm() : impl_(new My_package::impl()) {}
Given 3 classes.
class vehicle{
public:
void start();
}
class airplane: public vehicle{
void start();
void setRoute(route r);
void setAltitude(altitude a);
}
class boat: public vehicle{
void start();
void setRoute(route r);
}
Suppose we receive a parameter by command line that let us understand if we will manage an airplane or a boat.
Vehicle* v;
if (parameter == 1) {
v = new airplane();
v->setRoute(r);
v->setALtitude(a);
}
if (parameter != 1) {
v = new boat();
v->setRoute(r);
}
v->start();
Note that different methods are called for boat and airplane before start.
(Start is the only common method)
This code will not work because v doesn't contains methods setRoute/SetALtitude.
What's the correct way of implement this pattern?
You can easily do:
if(parameter != 1)
{
boat *b = new boat;
b->setRoute(r);
v = b;
}
and similar for airplane.
class __declspec(novtable) vehicle{
public:
virtual void start();
virtual void setRoute(route r) = 0;
virtual void setAltitude(altitude a) = 0;
};
class airplane: public vehicle{
virtual void start();
virtual void setRoute(route r);
virtual void setAltitude(altitude a);
};
class boat: public vehicle{
virtual void start();
virtual void setRoute(route r);
virtual void setAltitude(altitude a);
};
I'm not happy with the question title, but I couldn't describe it well. I'm putting implementation in the class declarations for sake of brevity.
I have a class like this:
class VisibleObject {
public:
void draw(sf::RenderWindow& rw) {
rw.draw(*shape.get());
}
virtual void setSize(sf::Vector2f) = 0;
protected:
std::shared_ptr<sf::Shape> shape;
}
sf::Shape is an abstract class. Then I have a derived class like so:
class Brick : VisibleObject {
Brick() {
shape.reset(new sf::RectangleShape());
}
void setSize(sf::Vector2f newSize) {
std::dynamic_pointer_cast<sf::RectangleShape>(shapes).get()->setSize(newSize);
}
}
sf::RectangleShape() is a concrete class that inherits from sf::Shape and setSize() is defined for it, not sf::Shape, which is why I need to cast.
Of course, I need to do some error handling, in the case that the dynamic cast fails and returns an empty shared_ptr.
I'm doing this because I wanted to be able to define the draw method just once, since in this simple game, every object will draw their member this way. Originally I left the shape out of the base class, and e.g. Brick would just have its own private sf::RectangleShape that could get instantiated on the stack; which was clean, but then the draw method had to be re-written for each object type.
This works, but is uglier to work with and introduces heap allocation. I also have shared_ptr overhead (I would have used unique_ptr, but I needed dynamic casting).
Is this the most appropriate way of doing what I'm trying to do?
It might be preferable to keep the interface an interface, and not start mandating implementation details. So just have an empty base class like so:
class VisibleObject
{
public:
~VisibleObject() {}
virtual void draw(sf::RenderWindow & window) = 0;
virtual void setSize(sf::Vector2f const & size) = 0;
};
You can stick the shape storage into the concrete class that implements this interface.
Moreover, Shape should provide a virtual resize method:
class Shape
{
public:
virtual ~Shape() {}
virtual void resize(sf::Vector2f const & size) = 0;
};
Now you can make, say, a VisibleShapeObject as an intermediate base class:
class VisibleShapeObject : public VisibleObject
{
public:
virtual void draw(sf::RenderWindow & window) override final
{
window.draw(*shape_);
}
virtual void setSize(sf::Vector2f const & size) override final
{
shape_->resize(size);
}
protected:
std::shared_ptr<Shape> shape_; // or unique_ptr<Shape>
};
Instead of mandating storage in std::shared_ptr<sf::Shape>, why not simply introduce a means of retrieving an sf::Shape& from the concrete class?
class VisibleObject {
virtual sf::Shape& getShape() = 0;
public:
void draw(sf::RenderWindow& rw) {
rw.draw(getShape());
}
virtual void setSize(sf::Vector2f) = 0;
};
class Brick : VisibleObject {
sf::RectangleShape shape;
sf::Shape& getShape() override { return shape; }
public:
void setSize(sf::Vector2f newSize) override {
shape.setSize(newSize);
}
};
It seems ridiculous to store via a pointer to base, introducing indirections and downcasts and reference count overhead, when you could just store a plain old member. In fact, if I'm understanding the problem correctly, you could probably use a template to generate concrete classes and avoid a lot of boilerplate:
class VisibleObject {
public:
virtual ~VisibleObject() {}
virtual void draw(sf::RenderWindow&) = 0;
virtual void setSize(sf::Vector2f) = 0;
};
template <typename Shape>
class VisibleConcreteObject : public VisibleObject {
Shape shape;
public:
void draw(sf::RenderWindow& rw) override /* final? */ {
rw.draw(shape);
}
void setSize(sf::Vector2f newSize) override /* final? */ {
shape.setSize(newSize);
}
};
typedef VisibleConcreteObject<sf::RectangleShape> Brick;
You haven't shared everything you are trying to do, but this it one way:
template<ShapeT>
class VisibleObject {
public:
void draw(sf::RenderWindow& rw) {
rw.draw(*shape.get());
}
virtual void setSize(sf::Vector2f) = 0;
protected:
std::shared_ptr<ShapeT> shape;
void reset(ShapeT* shape) {
this->shape = shape;
}
}
class Brick : VisibleObject<sf::RectangleShape> {
Brick() {
shape.reset(new sf::RectangleShape());
}
void setSize(sf::Vector2f newSize) {
shape->setSize(newSize);
}
}
There may be reasons why this doesn't work for you, but without more insight, I couldn't guess at what.
Can I change this code to make it work? Is it possible to combine template method pattern and multiple inheritance? It seems to be very convenient to implement different algorithms in different classes. Thank you.
class TBase {
public:
virtual void Do1() const = 0;
virtual void Do2() const = 0;
void Do() const {
Do1();
Do2();
}
};
class TFirstAlgorithm {
public:
void Do1() const {}
};
class TSecondAlgorithm {
public:
void Do2() const {}
};
class TAlgorithm
: public TBase
, public TFirstAlgorithm
, public TSecondAlgorithm
{};
Fundamentally, your problem is that TFirstAlgorith::Do1 isn't related to TBase::Do1 (and likewise TSecondAlgorithm::Do2 to TBase::Do2.
One possible way to fix that would be to make them related:
class TBase {
public:
virtual void Do1() const = 0;
virtual void Do2() const = 0;
void Do() const {
Do1();
Do2();
}
};
class TFirstAlgorithm : public virtual TBase {
public:
void Do1() const { }
};
class TSecondAlgorithm : public virtual TBase {
public:
void Do2() const { }
};
class TAlgorithm
: public TFirstAlgorithm
, public TSecondAlgorithm
{};
You can use implementations for Do1 and Do2 and call appropriate algorithm inside them.
class TBase {
public:
virtual void Do1() const = 0;
virtual void Do2() const = 0;
void Do() const {
Do1();
Do2();
}
};
class TFirstAlgorithm {
public:
void Do1() const {}
};
class TSecondAlgorithm {
public:
void Do2() const {}
};
class TAlgorithm
: public TBase
, public TFirstAlgorithm
, public TSecondAlgorithm
{
virtual void Do1() const { TFirstAlgorithm::Do1() ; }
virtual void Do2() const { TSecondAlgorithm::Do2() ; }
};