Perguntas sobre OOP em MQL5 - página 45

 
Dmitry Fedoseev:

Alguém pode explicar como esta inicialização dos campos é melhor do que isso:

é melhor do que isso:

E qual é o objetivo, afinal?

const podem ser inicializados.

 
Dmitry Fedoseev:

Alguém pode explicar como esta inicialização dos campos é melhor do que isso:

é melhor do que isso:

E qual é o objetivo, afinal?

No primeiro caso você tem inicialização, e no segundo caso - as operações são realizadas para campos inicializados padrão. Portanto, tudo depende do compilador, ou não faz diferença, ou uma carga de merda de ações extras em tempo de execução. A segunda variante é considerada má forma.
 
O = operador, como deveria, retorna valor r (5<(val=7) funciona), mas apenas com a semântica de transporte, não há uma aqui, e foi pedida, infelizmente, por isso também não há construtor de transporte.
 
Igor Makanu:

a questão é puramente teórica:

viram, possivelmente na SB, uma chamada de construtor como esta:

como este código seria diferente:

Descompactei, não vejo nenhuma diferença, então seja um pouco mais específico - o que ou por que podemos usar uma chamada forçada do construtor para objetos a1 e a2?

qual é a "conveniência" da primeira opção?

A primeira opção é chamada - Inicialização de valor, a segunda - Inicialização por padrão. Há sutilezas e diferenças dependendo do tipo de objeto (se é um agregado ou tem um construtor padrão, ...). Por exemplo, o resultado aqui será absolutamente diferente ao usar parênteses e sem eles:

#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;
}

Se você quer entender a teoria até seus ouvidos, vá aqui https://en.cppreference.com/w/cpp/language/initialization

ZS: não é tudo relevante para o mcl, mas como um entendimento do modelo de referência.

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:

Se você quer chegar até seus ouvidos em teoria, vá aqui https://en.cppreference.com/w/cpp/language/initialization

Ainda não é necessário, mas vou guardá-lo para saber onde ler a fonte.

Obrigado a todos!

Vladimir Simakov:
A segunda opção é considerada má forma.

Haverá o mesmo problema que eu encontrei - duplicação de código para inicialização de campos, quando for necessário escrever mais de um construtor na classe

se você usar a variante 2, você pode colocar o código duplicado em um método separado e chamar este método após as ações necessárias em cada construtor (eu tenho inicialização de classe por estrutura e variante 2 pelo nome do arquivo onde os dados desta estrutura são escritos (backup save))


Escrever esse código de repetição é ruim... não é interessante, mas o problema é que, se eu acrescentar um novo campo à classe, tenho que lembrar de inicializar este campo tantas vezes quanto os construtores - o fato, que não é conveniente, mas o fato, que você pode esquecer de fazê-lo N-vezes, é um problema, imho

 
Igor Makanu:

Ainda não é necessário, mas vou guardá-lo, para saber onde ler a fonte original.

Obrigado a todos vocês!

Haverá o mesmo problema que eu encontrei - duplicação de código para inicialização de campos, quando for necessário escrever mais de um construtor na classe

se você usar a variante 2, você pode colocar o código duplicado em um método separado e chamar este método após as ações necessárias em cada construtor (eu tenho inicialização de classe por estrutura e variante 2 pelo nome do arquivo onde os dados desta estrutura são escritos (backup save))


Escrever esse código de repetição é ruim... não é interessante, mas o problema é que, se eu acrescentar um novo campo à classe, tenho que lembrar de inicializar este campo tantas vezes quanto os construtores - o fato, que não é conveniente, mas o fato, que você pode esquecer de fazê-lo N-vezes, é um problema, imho

Uma macro que também pode ser paramétrica. Esquecer (eu mesmo sofro com isso), também trata com esta))))

 
Igor Makanu:

haverá o mesmo problema que encontrei - duplicação do código de inicialização de campo quando houver necessidade de escrever mais de um construtor na classe

Se você usar a variante 2, você pode colocar o código duplicado em um método separado e chamar este método após todas as ações necessárias em cada construtor (eu tenho inicialização de classe por estrutura e variante 2 pelo nome de um arquivo onde os dados desta estrutura são escritos (backup save))


Escrever esse código de repetição é ruim... Não é interessante, mas o problema é que, se eu acrescentar um novo campo à classe, terei que lembrar de inicializar este campo tantas vezes quanto há construtores - o fato, que não é conveniente, mas o fato, que você pode esquecer de fazê-lo N-times, é um problema, imho

Vamos lá, tudo pode ser resolvido:

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
        ...
    }
};

Não sou contra construtores padrão (ou inicialização padrão), mas se seu construtor deixa o objeto (bem, se não for um agregado idiota) em estado indefinido e depois você o inicializa através de algumas muletas, então você está fazendo tudo errado.

ZS: a propósito, você pode delegar o construtor nos profissionais, faltando, é claro

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

Vá lá, é solvível:

um pouco à minha frente, acabei de sentar-me no meu PC.

@Vladimir Simakov aconselha a inicializar campos de classe usando uma macro, não esquecer de inicializar corretamente, bem, sim - bom truque, mas o código vai ler como uma chamada para um método que inicializa campos, difícil de assumir que este é um bom tom...


Seu exemplo também não é o mais refinado, mas resolve o problema exatamente da forma como o fiz agora - um método de inicialização separado \.

imho, é uma questão de propósito - a forma correta de escrever uma classe base com todos os campos necessários, herdar dela, proteger o construtor e inicializar a classe base dos herdeiros e, assim, proteger do "esquecimento" - não há construtor padrão, certo? - assim, pelo menos você pode olhar para a mikrosoft se você procurar no Google "construtor protegido" - haverá um artigo


Meu problema é um pouco diferente, eu deixei a herança de propósito, para salvar o estado dos campos de classe em um arquivo, eu tenho 2 campos de 2 classes, e seu estado também é salvo no mesmo arquivo chamando os métodos apropriados. Tentei salvar tudo quando herdei de uma classe base, ficou muito confuso, reescrevi sem herança, tudo se tornou "transparente" agora.

 
Igor Makanu:

Um pouco à minha frente, acabei de sentar-me no PC.

@Vladimir Simakov aconselha a inicializar campos de classe usando uma macro, para não esquecer de inicializar corretamente, bem, sim, isso é um bom truque, mas o código vai ler como chamar um método que inicializa campos, difícil de assumir que esse é um bom tom...


Seu exemplo também não é o mais refinado, mas resolve o problema exatamente da forma como o fiz agora - um método de inicialização separado \.

imho, é uma questão de propósito - a maneira correta de escrever uma classe base com todos os campos necessários, herdar dela, proteger o construtor e inicializar a classe base dos herdeiros e, assim, proteger do "esquecimento" - não há construtor padrão, certo? - assim, pelo menos você pode olhar para a mikrosoft se você procurar no Google "construtor protegido" - haverá um artigo


Meu problema é um pouco diferente, deixei a herança de propósito, para salvar o estado dos campos de classe em um arquivo, tenho 2 campos de 2 classes e seu estado também é salvo no mesmo arquivo, chamando os métodos apropriados. Tentei salvar tudo quando o herdei de uma classe base, ficou muito complicado; reescrevi-o sem herança, tudo se tornou "transparente" agora.

O que há de tão confuso nisso?

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

O que há de tão confuso nisso?

foi exatamente disso que me afastei, e no início eu fiz

com esta abordagem - herdar de uma classe base, "onde tudo está" - tudo funciona, mas até que queremos tentar fazer vários campos de classe, e então queremos adicionar vários campos em cada classe de campo e pregar tudo com uma matriz dinâmica de classes

e então conseguiremos que não possamos implementar o próprio método Save(int hndl) em uma classe base - este método será na verdade uma interface, que, como discutido acima, não será de forma alguma necessária - você pode escrevê-lo sem interfaces

normalmente maximizo meus esforços em flexibilidade de código - mínimo de confusão - o resultado é um novo problema resolvido, que minha terminologia possa ser perdoada))))


o problema será, ao implementar o salvamento em arquivo, você precisa trabalhar o cabeçalho do arquivo, que deve descrever a quantidade total de diferentes tipos de entradas e então você não precisa perder a lógica / ordem de salvamento de dados, a fim de ler tudo corretamente.... e o final será se você mudar até mesmo um campo em uma classe

imho, a laboriosidade dessa herança "fácil" de uma classe base - se resume ao desenvolvimento e manutenção de um pequeno banco de dados, monitoramento constante das mudanças em qualquer classe