You will probably say the below solution doesn't solve your real issue, but it solves the simplified you presented ;-)
//--- template<typename T> class Pattern { private: T m_pattern; public: void Set(const T &s) {m_pattern=s;} void Get(T &s) {s=m_pattern;} }; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- Child1 cld1; cld1.type=1; cld1.S1=5.11; cld1.S2=6.3; printf("Child original type=%i S1=%f S2=%f",cld1.type,cld1.S1,cld1.S2); //--- save struct and read it again Pattern<Child1> obj; obj.Set(cld1); Child1 cld1Copy; obj.Get(cld1Copy); printf("Child copy type=%i S1=%f S2=%f",cld1Copy.type,cld1Copy.S1,cld1Copy.S2); }
You will probably say the below solution doesn't solve your real issue, but it solves the simplified you presented ;-)
The idea in general is an event hub.
The different structs represent different events (each with its own data).
Each class can register itself to the hub, asking for event type notifications from another class.
For instance, a strategy asks for event of stop-loss trigger from a trading supervisor class.
The trading supervisor knows it had an sl triggered, it informes the hub with the event struct (this is the save).
So, the event has to include some data, which order is stopped, the ticket, price etc.
The hub sends it to the client - which needs the restore of struct.
I will try to see if it can be of help, thanks.
Structs are always copied on assignment. This is in accordance with similar object-oriented languages like C++ or C#. So how should the values of the derived struct be preserved when it gets assigned to the super struct? Use classes instead.
Maybe someone knows templates better, I have a struct as template to CEventHub, but the struct itself has a constructor parameter, so this code is not compiled ("MqlEventDummy1 - wrong parameter count").
How do you specify that the template parameter has a parameter itself (and why is it needed at all) ?
thanks
enum ENUM_EVENT_TYPE { EVENT_TYPE_DUMMY1 }; template<typename T> class CEventHub { private: ENUM_EVENT_TYPE m_event_type; T m_event; public: void Set(const T &event) {m_event=event;} void Get(T &event) {event=m_event;} ENUM_EVENT_TYPE EventType() const {return(m_event_type);} }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ struct MqlEvent { private: ENUM_EVENT_TYPE event_type; public: MqlEvent(const ENUM_EVENT_TYPE type) {event_type=type;} }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ struct MqlEventDummy1 : public MqlEvent { MqlEventDummy1(const ENUM_EVENT_TYPE type); }; //+------------------------------------------------------------------+ //| constructor | //+------------------------------------------------------------------+ MqlEventDummy1::MqlEventDummy1(const ENUM_EVENT_TYPE type) : MqlEvent(type) { } //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- CEventHub<MqlEventDummy1> hub; // need specifying parameter for struct ?? }
I guess a constructor with parameters makes it a different type, so probably no way around but to specify NULL as default value to class constructor, so to imitate a non-parametrized class constructor.
Would have expected some syntax to handle that, but.. Can live with that.
Ok, tiredness..
First NULL
Second explicit value
struct MqlEvent { private: ENUM_EVENT_TYPE event_type; public: MqlEvent(const ENUM_EVENT_TYPE type=NULL) {event_type=type;} };
struct MqlEventDummy1 : public MqlEvent { MqlEventDummy1(); }; MqlEventDummy1::MqlDummy1() : MqlEvent(ENUM_EVENT_DUMMY1) { }
It works if you merge the data fields of all derived structs into the super struct like so:
enum EEventType { EMouseMoveEvent, EMessageEvent }; struct SEvent { protected: int i1; int i2; string s; public: int type; }; struct SMouseMoveEvent : public SEvent { SMouseMoveEvent(int x=0,int y=0) { type=EMouseMoveEvent; i1=x; i2=y; } int X() { return i1; } int Y() { return i2; } }; struct SMessageEvent : public SEvent { SMessageEvent(string msg="") { type=EMessageEvent; s=msg; } string Msg() { return s; } }; int OnInit() { SEvent ev; SMouseMoveEvent evmm(50,40); ev=evmm; SMouseMoveEvent evmm2=ev; Print(evmm2.X()," ",evmm2.Y()); SMessageEvent evmsg("text"); ev=evmsg; SMessageEvent evmsg2=ev; Print(evmsg2.Msg());
Here, because structs not support OO fully, the classes are used, but just as struct carriers.
The user creates the classes by supplying the struct, and recieves the data by retrieving the structs.
Each event has also a class, that has nothing public, but the struct it recieves in the constructor, and the struct it returns.
enum ENUM_EVENT_TYPE { EVENT_MOUSE_MOVE, EVENT_MESSAGE }; struct MqlEvent { ENUM_EVENT_TYPE event_type; }; class CEvent { private: ENUM_EVENT_TYPE event_type; protected: CEvent(const ENUM_EVENT_TYPE type) {event_type=type;} public: ENUM_EVENT_TYPE EventType() const {return event_type;} }; struct MqlEventMouseMove : public MqlEvent { int x; int y; }; class CEventMouseMove : public CEvent { private: int m_x; int m_y; public: CEventMouseMove(MqlEventMouseMove &event) : CEvent(EVENT_MOUSE_MOVE) {m_x=event.x; m_y=event.y;} bool ToStruct(MqlEventMouseMove &event) {event.x=m_x; event.y=m_y; return(true);} }; struct MqlEventMessage : public MqlEvent { string message; }; class CEventMessage : public CEvent { private: string m_message; public: CEventMessage(MqlEventMessage &event) : CEvent(EVENT_MESSAGE) {m_message=event.message;} bool ToStruct(MqlEventMessage &event) {event.message=m_message; return(true);} }; class CEventHub { private: CEvent *m_event; public: void SetEvent(CEvent *event) {m_event=event;} CEvent *GetEvent() {return(m_event);} }; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- MqlEventMouseMove mouseEvent; mouseEvent.x=15; mouseEvent.y=23; CEventMouseMove *objMouseEvent=new CEventMouseMove(mouseEvent); MqlEventMessage messageEvent; messageEvent.message="Mouse moved"; CEventMessage *objMessageEvent=new CEventMessage(messageEvent); CEventHub hub; hub.SetEvent(objMouseEvent); //--- get mouse event CEvent *event=hub.GetEvent(); if(event.EventType()==EVENT_MOUSE_MOVE) { CEventMouseMove *m=event; MqlEventMouseMove e; m.ToStruct(e); Print("Mouse x=",e.x," Mouse y=",e.y); } //--- send message hub.SetEvent(objMessageEvent); //--- get message event=hub.GetEvent(); if(event.EventType()==EVENT_MESSAGE) { CEventMessage *m=event; MqlEventMessage e; m.ToStruct(e); Print("Message=",e.message); } delete objMouseEvent; delete objMessageEvent; }
Looks like a pattern for that kind of problems maybe, reached to a combination between classes and structs.
Here, because structs not support OO fully, the classes are used, but just as struct carriers.
The user creates the classes by supplying the struct, and recieves the data by retrieving the structs.
Each event has also a class, that has nothing public, but the struct it recieves in the constructor, and the struct it returns.
It's about polymorphism and closure.
For the interested people who read this, polymorphism is when objects of different type are grouped as one. Think of a ferry that can load cars. It doesn't matter what cars, Ferraris, Beetles, anything. What matters is the size and weight so they can be loaded on board. Think of a big box that holds the car. No one yet is interested in the content of that box, its just size and weight that matters.Someone outside that box next harbor wants to know what is in it, and so studies the specs of it. "What's the type of the car? What's its ID? An
Alfa Romeo? Ok, I got someone waiting here, get it out of that box."
And this is difficult to achieve with structs, because they are copied on assignment, unlike classes. It's like you drive up with your car to the ferry and they make a copy of it, then throwing it away. Your car is now a boxed car copy, and the person who is waiting on the other side will get - yet another copy of it. Oh, you lost your sun glasses - you didn't specify it, sorry.
So instead of backing structs with classes, why not use classes first hand.
enum ENUM_EVENT_TYPE { EVENT_MOUSE_MOVE, EVENT_MESSAGE }; class CEvent { private: ENUM_EVENT_TYPE event_type; protected: CEvent(const ENUM_EVENT_TYPE type) {event_type=type;} public: ENUM_EVENT_TYPE EventType() const {return event_type;} }; class CEventMouseMove : public CEvent { public: int x; int y; CEventMouseMove(int px=0,int py=0) : CEvent(EVENT_MOUSE_MOVE) {x=px; y=py;} }; class CEventMessage : public CEvent { public: string message; CEventMessage(string pmessage="") : CEvent(EVENT_MESSAGE) {message=pmessage;} }; class CEventHub { private: CEvent *m_event; public: void SetEvent(CEvent *event) { if(CheckPointer(m_event)==POINTER_DYNAMIC) delete m_event; m_event=event; } CEvent *GetEvent() { return m_event; } CEventHub() { m_event=NULL; } ~CEventHub() { if(CheckPointer(m_event)==POINTER_DYNAMIC) delete m_event; } }; void OnStart() { CEventMouseMove *mouseEvent=new CEventMouseMove(15,23); CEventMessage *messageEvent=new CEventMessage("Mouse moved"); CEventHub hub; hub.SetEvent(mouseEvent); //--- get mouse event CEvent *event=hub.GetEvent(); if(event.EventType()==EVENT_MOUSE_MOVE) { CEventMouseMove *m=event; Print("Mouse x=",m.x," Mouse y=",m.y); } //--- send message hub.SetEvent(messageEvent); //--- get message event=hub.GetEvent(); if(event.EventType()==EVENT_MESSAGE) { CEventMessage *m=event; Print("Message=",m.message); } }Ok some things around new/delete would need to be sorted out but the hub class here is a stub anyway.
It's about polymorphism and closure.
For the interested people who read this, polymorphism is when objects of different type are grouped as one. Think of a ferry that can load cars. It doesn't matter what cars, Ferraris, Beetles, anything. What matters is the size and weight so they can be loaded on board. Think of a big box that holds the car. No one yet is interested in the content of that box, its just size and weight that matters.Someone outside that box next harbor wants to know what is in it, and so studies the specs of it. "What's the type of the car? What's its ID? An
Alfa Romeo? Ok, I got someone waiting here, get it out of that box."
And this is difficult to achieve with structs, because they are copied on assignment, unlike classes. It's like you drive up with your car to the ferry and they make a copy of it, then throwing it away. Your car is now a boxed car copy, and the person who is waiting on the other side will get - yet another copy of it. Oh, you lost your sun glasses - you didn't specify it, sorry.
So instead of backing structs with classes, why not use classes first hand.
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
I'm trying to get at something like structure hierarchy with a super struct and different structures derived from it.
Each derived structure has different kind of data, and there is a Pattern class that has the saving/reading methods for those different structures.
And so the structure is passed between different classes - one class saves it and another reads it and needs the data.
For instance, one class calls the save strurcture with structure A, and another class calls it to get structure A back.
The problem I'm facing is casting a structure to it's super losses it's data and when I try to convert back, it's lost as can seen by the output
I can use uchar arrays instead
Which gets the structure right, but the price to pay for that is that the typecasting back by the last CharArrayToStruct is not typesafe checked by compiler - I could write any struct in the function and it will compile:
Child2 cld2Copy; // retriever tries to retrieve a different struct then the saved one
CharArrayToStruct(cld2Copy,arr2); // should be cld1Copy which was previously saved, but compiler does not check
Almost sure there's no way, but anyway.
void & struct_object (could be the equivalent of void *) which would have accepted any struct does not seem to work on Mql5 like in it's own functions, for instance the void first parameter of that function is not Mql5 syntax:
The perfect solution would have been:
but of course not in Mql5