Questions on OOP in MQL5 - page 45

 
Dmitry Fedoseev:

Can someone explain how this initialisation of the fields is better than this:

is better than this:

And what is the point anyway?

const fields can be initialised.

 
Dmitry Fedoseev:

Can someone explain how this initialisation of the fields is better than this:

is better than this:

And what is the point anyway?

In first case you have initialization, and in second case - operations are performed for default initialized fields. So it all depends on compiler, either it makes no difference, or a shit-load of extra actions in run-time. In pluses the second variant is considered bad form.
 
The = operator, as it should, returns r-value (5<(val=7) works), but just with the carry semantics, there isn't one here, and it was asked for, sadly, so there is no carry constructor either.
 
Igor Makanu:

the question is purely theoretical:

have seen, possibly in SB, a constructor call like this:

how would this code be different:

I have unzipped it, I don't see any difference, then be a bit more specific - what or why can we use a forced constructor call for a1 and a2 objects?

what is the "convenience" of the first option?

The first option is called - Value initialization, the second - Default initialization. There are subtleties and differences depending on the type of the object (whether it is an aggregate or has a default constructor, ...). For example, the result here will be absolutely different when using brackets and without them:

#include <iostream>
using namespace std;
struct S {
        int i;
        int q;
        int f;
};
struct Q : S {
        Q():S() {}
        //Q() {}
};
int main() {
        Q s;
        cout << s.i << s.q << s.f << endl;
}

If you want to grasp the theory up to your very ears, go here https://en.cppreference.com/w/cpp/language/initialization

ZS: it's not all relevant to the mcl, but as an understanding of the reference model.

Initialization - cppreference.com
  • en.cppreference.com
Initialization of a variable provides its initial value at the time of construction. The initial value may be provided in the initializer section of a declarator or a new expression. It also takes place during function calls: function parameters and the function return values are also initialized. For each declarator, the initializer may be one...
 
Vict:

If you want to get up to your ears in theory, go here https://en.cppreference.com/w/cpp/language/initialization

Not necessary yet, but I'll save it so I know where to read the source.

Thanks all!

Vladimir Simakov:
In pluses, the second option is considered bad form.

There will be the same problem I encountered - duplication of code for initialization of fields, when it becomes necessary to write more than one constructor in the class

if you use variant 2, you can put the duplicated code in a separate method and call this method after the necessary actions in each constructor (I have class initialization by structure and variant 2 by the name of the file where data of this structure is written (backup save))


To write that repeating code is bad... it's not interesting, but the problem is, if I add a new field to the class, I have to remember to initialize this field as many times as constructors - the fact, that it's not convenient, but the fact, that you can forget to do it N-times, is a problem, imho

 
Igor Makanu:

Not necessary yet, but I'll keep it, I'll know where to read the original source.

Thank you all!

There will be the same problem I encountered - duplication of code for initialization of fields, when it becomes necessary to write more than one constructor in the class

if you use variant 2, you can put the duplicated code in a separate method and call this method after the necessary actions in each constructor (I have class initialization by structure and variant 2 by the name of the file where data of this structure is written (backup save))


To write that repeating code is bad... it's not interesting, but the problem is, if I add a new field to the class, I have to remember to initialize this field as many times as constructors - the fact, that it's not convenient, but the fact, that you can forget to do it N-times, is a problem, imho

A macro that can also be parametric. Forgetting (I suffer from it myself), also treats with this))))

 
Igor Makanu:

there will be the same problem I encountered - duplication of field initialization code when there is a need to write more than one constructor in the class

If you use variant 2, you can put the duplicated code in a separate method and call this method after the necessary actions in each constructor (I have class initialization by structure and variant 2 by the name of a file where data of this structure are written (backup save))


To write that repeating code is bad... It's not interesting, but the problem is, if I add a new field to the class, I'll have to remember to initialize this field as many times as there are constructors - the fact, that it's not convenient, but the fact, that you can forget to do it N-times, is a problem, imho

Come on, everything can be solved:

class Q {
    void ctr_base(T t, S s) {//make init tasks
        }
public:
    Q(T t, S s, int i) {
        // make base init
        ctr_base(t, s);
        // make additional tasks
        ...
    }
    Q(T t, S s, strint str) {
        // make base init
        ctr_base(t, s);
        // make additional tasks
        ...
    }
};

I'm not against default constructors (or default initialization), but if your constructor leaves the object (well, if it's not a dumb aggregate) in undefined state and then you doinitialize it via some crutches, then you're doing it all wrong.

ZS: by the way, you can delegating constructor in the pros, lacking of course

class Foo {
public: 
  Foo(char x, int y) {}
  Foo(int y) : Foo('a', y) {} // Foo(int) delegates to Foo(char,int)
};
 
Vict:

Come on, it's solvable:

a little ahead of me, just sat down at the PC.

@Vladimir Simakov's advice to initialize class fields using a macro, not to forget to initialize properly, well, yes - good trick, but the code will read like a call to a method that initializes fields, hard to assume that this is a good tone...


Your example isn't the most refined either, but it solves the problem exactly the way I did it now - a separate initialization method \.

imho, it's a question of purpose - the right way to write a base class with all the necessary fields, inherit from it, make the constructor protected and initialize the base class from the heirs and thus will be protection from "forgetting" - there is no default constructor? - so at least you can look at mikrosoft if you google "protected constructor" - there will be an article


My problem is a little different, I purposely left the inheritance, to save the state of the class fields to a file, I have 2 fields of 2 classes, and their state is also saved in the same file by calling the appropriate methods. I tried to save it all when I inherited from a base class, it got very messy, I rewrote it without inheritance, everything became "transparent" now.

 
Igor Makanu:

A little ahead of me, just sat down at the PC.

@Vladimir Simakov's advice to initialize class fields using a macro, in order not to forget to initialize properly, well, yes - good trick, but the code will read like a call to a method that initializes fields, hard to assume how good is the tone...


Your example isn't the most refined either, but it solves the problem exactly the way I did it now - a separate initialization method \.

imho, it's a question of purpose - the right way to write a base class with all the necessary fields, inherit from it, make the constructor protected and initialize the base class from the heirs and thus will be protection from "forgetting" - there is no default constructor? - so at least you can look at mikrosoft if you google "protected constructor" - there will be an article


My problem is a little different, I purposely left the inheritance, to save the state of the class fields to a file, I have 2 fields of 2 classes, and their state is also saved in the same file by calling the appropriate methods. I tried to save everything when I inherited it from a base class, it got very complicated; I rewrote it without inheritance, everything became "transparent" now.

What's so confusing about it?

...
virtual void CBase::Save(int hndl){...}
...
CObj:public CBase
...
void CObj::Save(int hndl){
   CBase::Save(hndl);
   ...
}
 
Vladimir Simakov:

What's so confusing about it?

that's exactly what i got away from, and at first i did

with this approach - to inherit from a base class, "where everything is" - everything works, but until we want to try making several class fields, and then we want to add several fields in each field-class and nail it all with a dynamic array of classes

and then we'll get that we can't implement the Save(int hndl) method itself in a base class - this method will actually be an interface, which, as discussed above, won't be needed at all - you can write it without interfaces

i usually maximize my efforts on code flexibility - minimum of fuss - result is a new problem solved, may my terminology be forgiven)))


the problem will be, when implementing saving to file, you need to work out the file header, which should describe the total amount of different types of entries and then you need not to lose the logic / order of data saving, in order to read everything correctly.... and the finale will be if you change even one field in one class

imho, the laboriousness of such "easy" inheritance from a base class - comes down to development and maintenance of a small database, constant monitoring of changes in any class