I am writing a simple graphics editor. There are 3 buttons on the panel, by pressing which I draw a square, circle or line. There are 3 button handlers that change the state and 3 mouse event handlers in the class responsible for drawing the workspace.
void Cpr111View::OnCirc()
{
state = 1;
}
void Cpr111View::OnLine()
{
state = 2;
}
void Cpr111View::OnRect()
{
state = 3;
}
To shorten the question, I will give only one handler out of 3.
void Cpr111View::OnMouseMove(UINT nFlags, CPoint point)
{
if (state==2)
{
int oldmode;
CClientDC *pDC = new CClientDC(this);
if (nFlags && MK_LBUTTON)
{
oldmode = pDC->GetROP2();
pDC->SetROP2(R2_NOT);
pDC->MoveTo(begin.x, begin.y);
pDC->LineTo(oldmouse.x, oldmouse.y);
pDC->MoveTo(begin.x, begin.y);
pDC->LineTo(point.x, point.y);
oldmouse = point;
pDC->SetROP2(oldmode);
CView::OnMouseMove(nFlags, point);
}
}
if (state == 1)
{
….
}
if (state == 3)
{
….
}
void Cpr111View::OnLButtonUp(UINT nFlags, CPoint point)
{
}
void Cpr111View::OnLButtonDown(UINT nFlags, CPoint point)
{
}
Here is a drawing system. I want to do it without states. That is, create an abstract class Figure. With three virtual methods per render:
Class Figure
{
public:
void virtual MouseMove()=0;
void virtual ButtonUp()=0;
void virtual ButtonDown()=0;
}
And from him in the classes of figures to override these methods.
Class Recatngle:public Figure
{
public:
void MouceMove() override;
...
}
Then, when the button is clicked, create an object of the corresponding class, then the button handler will look like this:
void Cpr111View::OnRect()
{
figure = new Rectangle();
}
And when drawing, the mouse handler will simply call the method of the corresponding class:
void Cpr111View::OnMouseMove(UINT nFlags, CPoint point)
{
figure - > MouseMove();
}
In order for figure to be available in two different methods, we declare it in the class:
class Cpr111View : public CView
{
public:
Figure figure;
…
}
This is how I want to do it, but the problem is that it can't be done that way. At a minimum, you cannot declare an abstract class variable. Then what type should it be if I am going to write a pointer to different classes into it? How to implement this architecture correctly, or maybe there are better ideas?
CodePudding user response:
Using this way of polymorphic calls in C requires to use reference sematics. I advise to read about it. E.g.: https://isocpp.org/wiki/faq/value-vs-ref-semantics
So it class Cpr111View
, you have to keep your Figure
member by pointer, or by refernce.
In order to avoid having to manually manage the object, you should use a smart pointer like std::unique_ptr
(or std::shared_ptr
if you need to share ownership):
#include <memory> // for std::unique_ptr
class Cpr111View : public CView
{
public:
std::unique_ptr<Figure> figure;
//…
}
Of course you will need to allocate it before using it. Instead of:
figure = new Rectangle();
use:
figure = std::make_unique<Rectangle>();
The method calls stay the same as in your code, e.g.:
figure->MouseMove();
If you not familiar with smart pointers in C , I recomend to read about it. E.g.: What is a smart pointer and when should I use one?