OOP, plantillas y macros en mql5, sutilezas y usos - página 2

 
Ilya Malev:

He tenido muchas situaciones de declarar campos estáticos en clases que se inicializan globalmente (antes de OnInit), siempre y cuando se vuelva a declarar el campo estático justo después de la descripción de la clase, y antes de declarar la variable global de su instancia, nunca hubo ningún problema con la inicialización del campo estático (porque en este caso se considera global y se inicializa antes que la instancia de la clase según tengo entendido). Por lo tanto, sólo hay que rechazar la declaración de variables estáticas dentro de los métodos y funciones y no hay ningún problema.

Sí, así es, se inicializa de inmediato en las clases regulares. Pero no se inicializa en las plantillas:

template<typename T>
class A
{
 public: 
  static int a;
};

template<typename T>
int A::a=10;

int f() { return A<int>::a; }

int a= f();

void OnStart()
{
  Print(a); // Результат: 0
};
 
Alexey Viktorov:

No puedes negarte completamente a declarar variables estáticas dentro de métodos y funciones, pero al menos no inicialices otras variables estáticas con aquellos métodos o funciones que contengan variables estáticas.

En este ejemplo, al principio la variable estática int b será inicializada pero la variable estática int f dentro de la función int a(int n) no será inicializada todavía y como resultado obtendremos un galimatías.

Por cierto, sí, es un error más. Es decir, además de inicializar por separado las variables estáticas/globales, el código inicializa las propias variables estáticas en un orden incorrecto. Así que dices "no inicializar otras variables estáticas con aquellos métodos o funciones que contienen variables estáticas" - ¿cómo sugieres realmente observar esto? Cada función es independiente y existe por sí misma. Tiene su propia aplicación, que está sujeta a cambios. Supongamos que antes no tenía una variable estática, y luego decides añadirla, lo que significa que algo puede ir mal en alguna parte, porque fue diseñado para no tener una variable estática en la función. ¿Y cómo vas a controlar todo esto?

 
No entiendo este tipo de decisiones de renunciar a esto o aquello. ¿Por qué renunciar? ¿Para qué? Cuando puedes resolver el problema y no negarte nada. Bueno, cada uno tiene su propia elección...
 
Alexey Navoykov:

Por cierto, sí, se trata de otro error, es decir, además de la inicialización separada de las remediciones estáticas/globales, inicializa las propias variables estáticas en el orden equivocado. Así que dices "no inicializar otras variables estáticas con aquellos métodos o funciones que contienen variables estáticas" - ¿cómo sugieres realmente observar esto? Cada función es independiente y existe por sí misma. Tiene su propia aplicación, que está sujeta a cambios. Supongamos que antes no tenía una variable estática, y luego decides añadirla, lo que significa que algo puede ir mal en alguna parte, porque fue diseñado para no tener una variable estática en la función. ¿Y cómo vas a controlar todo esto?

No es un problema en absoluto. Basta con rechazar la inicialización de las variables por parte de las funciones y todo caerá en su sitio.

int a(int n)
{
 static int f=7;
 return(f+=n);
}

void OnTick()
{
 static int b;
 b=a(9);
}
Funcionará bien. ¿Cuál es el problema? ¿Una línea?
 
Alexey Viktorov:

Funcionará para un hoot y un holler. ¿Cuál es el problema? ¿Una línea?

¿Entonces entiendes que la lógica es diferente aquí? ¿Por qué declarar b como estática si le asignas un valor en cada llamada?
 
Alexey Navoykov:
Entonces, ¿entiendes que la lógica es diferente aquí? ¿Por qué declarar b estática si le asignas un valor en cada llamada?

Estoy de acuerdo. Lo he estropeado un poco con las prisas. Pero a la variable 'b' se le puede asignar un valor bajo alguna condición y en lugar de 9 valores se puede pasar a la función dependiendo de la condición.


Pero en tu ejemplo, ¿la variable 'a' debe ser inicializada globalmente?

template<typename T>
class A
{
 public: 
  static int a;
};

template<typename T>
int A::a=10;

int f() { return A<int>::a; }

int a= f();

void OnStart()
{
  Print(a); // Результат: 0
};

No hay otra opción en el script, y en el Asesor Experto puedes declarar la variable a nivel global e inicializarla en OnInit()

Basta con entender y observar la secuencia de inicialización. Primero las variables globales, luego las estáticas y después las locales, según aparezcan en el código.

Este mismo ejemplo viola la recomendación de la documentación de no inicializar variables con funciones. Para los desarrolladores era más fácil escribir esa advertencia que explicar dónde se puede y dónde no.

Elimine la estática de su ejemplo y obtenga el resultado deseado.

 
Alexey Viktorov:

Pero, ¿la variable "a" de tu ejemplo debe ser inicializada globalmente?

No necesariamente, pero es más conveniente para mí. Si es una constante (y las constantes globalmente visibles se declaran en su mayoría, si el código es inteligente), entonces no hay otra opción.

No hay otra opción en el script, y en el EA puedes declarar una variable globalmente e inicializarla en OnInit()

Bastacon entender y observar la secuencia de inicialización. Primero las variables globales, luego las estáticas y después las locales, según aparezcan en el código.

Este mismo ejemplo viola la recomendación de la documentación de no inicializar variables con funciones. Para los desarrolladores era más fácil escribir esa advertencia que explicar dónde se puede y dónde no.

Elimine la estática de su ejemplo y obtenga el resultado deseado.

Con respecto a todo lo que está en amarillo, tengo una pregunta: ¿por qué? Ya he encontrado cómo resolver el problema.
 
Actualizado el archivo de la página anterior. Se ha corregido un pequeño fallo.
 
Alexey Navoykov:

No necesariamente, pero es más conveniente para mí. Si es una constante (y la visibilidad global en su mayoría declara constantes, si el código es inteligente), no hay otra opción.

Con respecto a todo lo que está en amarillo, tengo una pregunta: ¿por qué? Ya he encontrado cómo resolver el problema.

Has encontrado la manera de crearlo.

 
Alexey Navoykov:

Sí, así es, en las clases regulares se inicializa inmediatamente. Pero en las clases de plantilla no lo es:

Estás intentando utilizar un campo estáticode una clase en la fase de inicialización antes de que se haya creado al menos una instancia de esa clase. En mi opinión, esto es una perversión... Así es como funciona normalmente:

template<typename T>
class A
{
 public: 
  A(){}
  static int a;
  int f(){return a;}
};

template<typename T>
int A::a=10;

A<int> _a;


int a= _a.f();

void OnStart()
{
  Print(a);
};
El principio de encapsulación en general sugiere que estos campos deben estar ocultos en lugar de ser públicos.