Type() method of CObject derivatives in Standard library, always return 0 when casting to CObject. - page 2
You are missing trading opportunities:
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
Registration
Log in
You agree to website policy and terms of use
If you do not have an account, please register
I'm not trying to crush your dreams but there's no chance for this to happen in MQL5, and it isn't a matter of whether or not it could be implemented, it shouldn't be implemented. You should never have protected mutable members in an abstract base class. Do you know how many descendant classes already contain a "m_type" member? I think half of all my custom classes would break if MQ ever did such a thing. Your only chance here is if MQ ever releases an update to allow for multiple inheritance, and even then you'd still have to roll your own Control classes. So if you are concerned with "performance" issues associated with dynamic casting (which I can assure you, you shouldn't be) then you should K.S.S. and subclass each control, assign it a unique int ID, and implement the `Type` method because after-all, that is the "proper" way to do it.
You've already crushed my dreams ;) but apart from kidding, we are talking technically and according to the recent policy of Metaquotes, development issues are to be discussed in forum.
Abstract classes are used for creating generic entities, that you expect to use for creating more specific derived classes. An abstract class can only be used as the base class for some other class, that is why it is impossible to create an object of the abstract class type.
A class which contains at least one pure virtual function in it is abstract. Therefore, classes derived from the abstract class must implement all its pure virtual functions, otherwise they will also be abstract classes.
I had a few minutes waiting for a trade setup... Merry Xmas.
What about private members of derivatives of CWndContainer and CWndClient class?
For example CCheckGroup has a private "m_rows" array of CCheckBox type, this way one should clone CCheckGroup as UiCheckGroup and declare the "m_rows" array as a UiCheckBox private member, this goes to all standard library base and derivative classes.
I'm not trying to crush your dreams but there's no chance for this to happen in MQL5, and it isn't a matter of whether or not it could be implemented, it shouldn't be implemented. You should never have protected mutable members in an abstract base class. Do you know how many descendant classes already contain a "m_type" member? I think half of all my custom classes would break if MQ ever did such a thing. Your only chance here is if MQ ever releases an update to allow for multiple inheritance, and even then you'd still have to roll your own Control classes. So if you are concerned with "performance" issues associated with dynamic casting (which I can assure you, you shouldn't be) then you should K.S.S. and subclass each control, assign it a unique int ID, and implement the `Type` method because after-all, that is the "proper" way to do it.
Your custom classes that follow the logic in#9 won't fail if a "m_type" protected member is introduced in a future update, since they override the Type() method and they ignore a "m_type" member.
There is no clean way to detect the object type of the CObject derivatives, this is highly needed when iterating through items of a CObject array or a CArrayObj instance.
The "Type(void)" public method is defined virtually in the base class CObject.
The method is defined for all derivatives in standard library, here are some examples:
Suppose that we have created a CAppDialog and we want to iterate through its controls, first we may assign controls to local pointer by the following code:
But there is no clean way to detect the control type, so we can't cast it to the correct class.
If the Type() method is called for the pointer, it will always return 0, because CWnd has not a Type() method and the Type() method of CObject always return 0.
The work around would be a protected member, m_type, in CObject, then all constructors should initialize it by their unique identifier, and the virtual Type() method of derivatives calls the parent method and returns the value of m_type.
Then we can simply cast it to the correct class,
I agree. But have you tried just using typename() instead? It is a less optimal solution since the function returns a string. However, if your primary aim is to simply identify the instance of the control you are dealing with, I think this is the way to go without having to clone the standard library or even insert additional protected members.
The type is lost when casting, it always return the type which the variable is declared.
The type is lost when casting, it always return the type which the variable is declared.
I see. My bad. The controls are stored in CObject*, so it would return "CObject*" as well.
Another way I am thinking atm is to use an overloaded method for adding objects. On the code below, it uses the AddControl() method rather than the Add() method of CWndContainer, where each specific type of control is mirrored to m_controls, and are stored in different instances of CArrayObj. It is not a pretty neat solution, but at least when you are iterating on each of the controls array, you already know what type of instance you are dealing with. And you no longer need to clone or remake the entire standard library. One of the problems though is ambiguous calls. You either need to create CArrayObj instances for those types, or use Add() in case you don't want to track them.I'd be interested to hear other solutions some might have regarding this problem, without cloning or remaking the standard library, as this can impact some of my existing programs. My thanks to you for raising this issue.
My friends, I think we are confusing virtual methods for regular methods. Let us not forget what makes virtual methods special, polymorphism. Mohammad, type is not lost when casting. There's a reason the base class implements the abstraction of type identification through virtual methods and not via a protected member. First let's look at a basic example of polymorphism and how we actually do get the result we expect.
As you can see, each dynamic object has been casted and stored as a CObject* pointer in the array. From the loop we call the virtual method Type on the CObject* pointers without casting the objects back to their original pointers, and we do in fact get the proper Type ID integer return.
The real reason you are having so much trouble is because you are trying to access newly added control objects to CAppDialog via the Controls method, but they aren't stored there. They are instead added to m_client_area which is a private member of CDialog, which then becomes inaccessible as soon as you subclass CAppDialog. In order for this to work the way you need it to, you will need to overload the Add method in your Dialog subclass and add a protected CArrayObj member to store pointers to the controls for future iteration. I've taken the liberty to update the uicontrols.mqh so now all you have to do is replace CAppDialog with UiAppDialog in your code (*also replace all CControls with UiControls) and you can then iterate your newly added controls via the new m_ui_controls member.
Example:
And of course... the new include
My friends, I think we are confusing virtual methods for regular methods. Let us not forget what makes virtual methods special, polymorphism. Mohammad, type is not lost when casting. There's a reason the base class implements the abstraction of type identification through virtual methods and not via a protected member. First let's look at a basic example of polymorphism and how we actually do get the result we expect.
As you can see, each dynamic object has been casted and stored as a CObject* pointer in the array. From the loop we call the virtual method Type on the CObject* pointers without casting the objects back to their original pointers, and we do in fact get the proper Type ID integer return.
The real reason you are having so much trouble is because you are trying to access newly added control objects to CAppDialog via the Controls method, but they aren't stored there. They are instead added to m_client_area which is a private member of CDialog, which then becomes inaccessible as soon as you subclass CAppDialog. In order for this to work the way you need it to, you will need to overload the Add method in your Dialog subclass and add a protected CArrayObj member to store pointers to the controls for future iteration. I've taken the liberty to update the uicontrols.mqh so now all you have to do is replace CAppDialog with UiAppDialog in your code (*also replace all CControls with UiControls) and you can then iterate your newly added controls via the new m_ui_controls member.
Example:
And of course... the new include
You're right. thanks for your time and describing in details. By the way, by the word "type is lost when casting" I meant the name returned by typename as following:
You're right. thanks for your time and describing in details. By the way, by the word "type is lost when casting" I meant the name returned by typename as following:
No worries. Fair enough, I thought you were saying that casting back to CObject would result in Type always returning 0 despite overriding the virtual method. I'm glad we cleared that up 😁
My friends, I think we are confusing virtual methods for regular methods. Let us not forget what makes virtual methods special, polymorphism. Mohammad, type is not lost when casting. There's a reason the base class implements the abstraction of type identification through virtual methods and not via a protected member. First let's look at a basic example of polymorphism and how we actually do get the result we expect.
As you can see, each dynamic object has been casted and stored as a CObject* pointer in the array. From the loop we call the virtual method Type on the CObject* pointers without casting the objects back to their original pointers, and we do in fact get the proper Type ID integer return.
The real reason you are having so much trouble is because you are trying to access newly added control objects to CAppDialog via the Controls method, but they aren't stored there. They are instead added to m_client_area which is a private member of CDialog, which then becomes inaccessible as soon as you subclass CAppDialog. In order for this to work the way you need it to, you will need to overload the Add method in your Dialog subclass and add a protected CArrayObj member to store pointers to the controls for future iteration. I've taken the liberty to update the uicontrols.mqh so now all you have to do is replace CAppDialog with UiAppDialog in your code (*also replace all CControls with UiControls) and you can then iterate your newly added controls via the new m_ui_controls member.
Example:
And of course... the new include
With the help of your example, I realized that the real reason is that not all derivative classes have a virtual Type() method.
I searched in Include files and found that the method is defined only for chart objects, indicators and arrays.
That's why calling Type() method on controls always return 0.
Your logic fills the GAP, but not fully, because each controls has its own m_controls array of CArrayObj, keeping the pointer to the private child controls, the pointer to child controls are accessible through Control() public method, so we can iterate them.
Suppose that I have a subclass of CCheckGroup as UiCheckGroup, it has a private member CCheckBox, I have no way to find out the type of controls in the UiCheckGroup.
So I believe the work around would be defining a virtual Type() method for each control type in a future update of standard library.