English Русский Deutsch 日本語 Português
preview
Del básico al intermedio: Sobrecarga

Del básico al intermedio: Sobrecarga

MetaTrader 5Ejemplos |
296 1
CODE X
CODE X

Introducción

El contenido expuesto aquí tiene un propósito puramente didáctico. En ningún caso debe considerarse una aplicación final, cuyo objetivo no sea el estudio de los conceptos mostrados aquí.

En el artículo anterior, «Del básico al intermedio: Punto flotante», hablamos de lo más básico sobre punto flotante. Como ese material es, a mi parecer, algo importante de ser debidamente comprendido, lo presenté en este inicio del recorrido. Esto se debe a que entender cómo funcionan los tipos float y double es algo imprescindible para poder comprender otras cuestiones futuras.

Aunque ese contenido sea solo lo básico de lo que realmente necesita ser muy bien asimilado por quien desea convertirse en un buen programador, ya será suficiente para que podamos hablar de otras cosas. A pesar de todo, muy probablemente, en un momento oportuno, necesitaremos volver a hablar más sobre punto flotante, pero con un contenido un poco más avanzado. Pero esto es algo para pensar en un momento futuro.

Sin embargo, ese artículo, a mi parecer, ya ayudará a muchos a entender que el hecho de que estemos manipulando un programa, o mejor dicho, una plataforma de negociación, donde equivocarse significa perder dinero, no podemos intentar ser totalmente exactos en nuestras convicciones. Esto se debe a que el propio punto flotante nos impide ser totalmente exactos y precisos. Todo lo que podemos hacer es intentar estar lo más cerca posible de un valor que consideramos adecuado o justificable, esto para poder efectuar una compra o venta de un dado símbolo o producto financiero.

Bien, pero estas cuestiones tienen mucho más que ver con operadores o usuarios de una plataforma que con nuestra actividad principal, que, en este caso, es la programación. Nosotros, como programadores, debemos alertar a los usuarios de nuestras aplicaciones que existe, sí, un riesgo incorporado en los cálculos. Sin embargo, depende del usuario u operador ajustar y analizar si los datos reportados de hecho tienen sentido para él, efectuar una compra o venta en un momento dado.

Sin embargo, todavía no veo que tengamos una base suficientemente construida y sólida como para que podamos empezar a hablar sobre cómo programar o implementar un indicador o un Asesor Experto, también llamado robot. A pesar de que ya tengamos una buena noción de lo que es necesario y se puede hacer, a mi entender, podemos acabar con las manos atadas en ciertos momentos. Esto se debe a que hay cosas que aún no han sido explicadas. Y las mismas, de hecho, son necesarias en diversos momentos y para diferentes propósitos. Muchas veces, nos permiten hacer cosas que, sin el conocimiento adecuado, no sería posible realizar.

Y como no quiero, en artículos futuros, estar explicando ciertos detalles que pueden resultar tediosos y pesados, quiero construir una base completa y perfectamente sólida para, de hecho, presentar materiales más avanzados. Esto hará tanto los artículos más interesantes como también ayudará a ofrecer un contenido de mejor calidad. Ya que, al no necesitar explicar ciertos detalles, puedo centrarme en transmitir aún más conocimiento en los próximos artículos.

Aún falta explicar algunas cosas que, para muchos principiantes, pueden ser bastante complicadas. Sin embargo, es algo que realmente hay que explicar antes de que progresemos a un nivel superior.

Así como se hizo con respecto a arrays y cadenas, donde mostré que una cosa lleva a la otra, también existe la necesidad de explicar otro recurso antes de que hablemos de un recurso un poco más avanzado. Esto por la simple razón de que tendrá mucho más sentido entender cómo un recurso dado, aparentemente confuso, nos permite generar uno que muchos principiantes no utilizan por no entenderlo, viéndose forzados a crear una serie de rutinas, funciones y procedimientos que, muchas veces, son completamente innecesarios en un código más elaborado. O, mejor dicho, un código hecho por un programador con un mejor conocimiento sobre cómo crear algo usando este o aquel lenguaje. En nuestro caso, MQL5.

Entonces, para separar las cosas de manera adecuada, pasemos a un nuevo tema.


Entender qué es una sobrecarga

Si hay algo que hace que muchos programadores principiantes, o incluso un programador ocasional, se queden completamente perdidos y sin entender absolutamente nada de un código, es cuando, dentro de un mismo código, tenemos dos funciones o procedimientos con un mismo nombre. Sí, este tipo de cosa ocurre y, cuando sucede, deja a muchos programadores con menos experiencia o con menos conocimiento completamente perdidos, sin poder corregir, mejorar o incluso crear un código con base en otro.

Este tipo de cosa, aunque para ojos inexpertos parezca algo extremadamente confuso y sin ninguna lógica, es totalmente posible, permitido y aceptado por el compilador, siempre y cuando tú sigas ciertas reglas simples.

Como sé y entiendo que muchos deben estar diciendo que estoy loco o que perdí completamente la noción de lo que puedo estar diciendo, ya que muchos no tienen idea de cómo usar dos llamadas con objetivos ligeramente diferentes pero que contienen el mismo nombre, vamos a ver un ejemplo muy simple. Pero muy simple de verdad, solo para demostrar esto que quiero decir y voy a explicar.

Ahora, miremos el código justo abajo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(Sum(10, 25));
07.     Print(Sum(-10, 25.));
08. }
09. //+------------------------------------------------------------------+
10. ulong Sum(ulong arg1, ulong arg2)
11. {
12.     Print(__FUNCTION__, "::", __LINE__);
13.     return arg1 + arg2;
14. }
15. //+------------------------------------------------------------------+
16. double Sum(double arg1, double arg2)
17. {
18.     Print(__FUNCTION__, "::", __LINE__);
19.     return arg1 + arg2;
20. }
21. //+------------------------------------------------------------------+

Código 01

Y entonces, mi estimado lector, quiero que mires este código 01 y respondas con toda sinceridad, antes de ver el resultado de la ejecución: ¿Cómo funcionará realmente este código? O, para dejarlo más claro, ya debes saber que, cuando usamos la llamada Print en un código, queremos imprimir un valor cualquiera en el terminal de MetaTrader 5. Y aquí tenemos cuatro llamadas al procedimiento de biblioteca Print.

Entonces, reformulando la misma pregunta que se hizo anteriormente: ¿Puedes decirme qué se imprimirá en el terminal? Obviamente, puedes mirar las líneas seis y siete y decir: Bien, se imprimirá el valor 35 y el valor 15. Pero esto es la parte obvia de la operación. La parte que me interesa es saber cuál de las dos funciones será ejecutada: ¿la función Sum de la línea diez o la función Sum de la línea dieciséis? Hum, déjame ver. Vaya, pero esto no va a compilar, ya que tenemos dos funciones con el mismo nombre, tanto en la línea diez como en la línea dieciséis. ¿Pensaste que ibas a pillarme en esta?

Bueno, mi estimado lector, de hecho, y no dejas de tener toda la razón, esto sería realmente una trampa, ya que dos funciones o procedimientos NO PUEDEN TENER EL MISMO NOMBRE. Esto es un hecho, y quien diga lo contrario estará mintiendo o, como mínimo, ocultando algo. Sin embargo, esto no se aplica aquí, por más extraño que pueda parecer. Estas dos funciones Sum, presentes en las líneas diez y dieciséis, NO SON LA MISMA COSA. Aunque ambas hagan el mismo trabajo y lo ejecuten correctamente, el compilador no las ve como una sola, sino como dos funciones distintas, aunque tengan el mismo nombre.

Cierto, ahora sí estoy realmente confundido, pues, para mí, dos funciones o procedimientos no podrían tener el mismo nombre, esto cuando vayamos a usarlos en un mismo código. Esto es verdad, no pueden, pero aquí estamos haciendo lo que se conoce como sobrecarga de funciones o procedimientos.

Esta cuestión de la sobrecarga es uno de los temas que más alegría me da al programar. Esto se debe a que, si se planifica bien, la sobrecarga nos permite implementar códigos mucho más legibles. Si bien existen formas mejores de hacer esto, sin entender la sobrecarga que estás viendo en este código 01, es prácticamente, por no decir imposible, entender otro recurso presente en el lenguaje MQL5. Pero dejemos eso para otro momento. Primero, vamos a entender qué es y cómo funciona la sobrecarga.

La sobrecarga es exactamente esto que estás viendo en las líneas diez y dieciséis de este código 01. Cuando lo ejecutes, generará lo que se muestra en la imagen justo abajo.

Imagen 01

Lo que nos interesa aquí no es el valor que será impreso por las líneas seis y siete, sino estos valores que están siendo destacados en la imagen. Estos son los datos que, de hecho, nos interesan aquí y en este momento. Nota que, en un caso, nos estamos refiriendo a la línea 12 y, en otro, a la línea 18. ¿Por qué? El motivo es el tipo de valor empleado en las llamadas de las líneas seis y siete. Cuando el compilador esté intentando generar el ejecutable, mirará estos valores y dirá: Bien, este valor encaja con este parámetro esperado por esta función; aquel valor encaja con aquel otro parámetro. Y así va resolviendo las llamadas, de manera que podemos tener llamadas con un mismo nombre. Sin embargo, y esta es la parte importante, los argumentos o parámetros esperados NO PUEDEN SER IGUALES. Pueden tener cierta similitud, pero deben ser diferentes en número o que uno de ellos sea de tipo distinto. De lo contrario, el compilador no podrá entender hacia dónde debe dirigirse el código, y esto se considera un error.

Observa que, en este caso, tanto Sum presente en la línea diez como el de la línea dieciséis tienen tipos diferentes siendo utilizados. Como el segundo argumento de la línea siete es de tipo distinto al entero, el compilador sabe que, en este caso, deberá llamar a la función donde se espera un tipo punto flotante en ese argumento.

Para fijar este conocimiento, veamos otro caso.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(Sum(10, 25));
07.     Print(Sum((char)-10, 25));
08. }
09. //+------------------------------------------------------------------+
10. ulong Sum(int arg1, ulong arg2)
11. {
12.     Print(__FUNCTION__, "::", __LINE__);
13.     return arg1 + arg2;
14. }
15. //+------------------------------------------------------------------+
16. double Sum(char arg1, ulong arg2)
17. {
18.     Print(__FUNCTION__, "::", __LINE__);
19.     return (double)(arg1 + arg2);
20. }
21. //+------------------------------------------------------------------+

Código 02

Ahora, presta atención, pues este código 02 tiene el mismo resultado que se muestra en la imagen 01. Sin embargo, aquí ya no estamos tratando con algo tan simple como antes, siendo este un tipo de código que muchos programadores con menos experiencia consideran demasiado confuso. Y tratan de modificarlo con el fin de corregir la aparente confusión que está siendo generada. No obstante, al hacer esto, terminan creando un problema para sí mismos, ya que el resultado no es el mismo que el esperado o logrado por el creador del código. Por esta razón, antes de que intentes modificar un código desconocido, mi estimado lector, intenta estudiar cómo funciona. Si es posible, ejecútalo de forma controlada, esto con el fin de poder entender el flujo de ejecución. Pues puede que algo se te esté escapando, y tratar de cambiar algo antes incluso de entenderlo es uno de los mayores errores que un principiante puede cometer.

Ahora, entendamos lo siguiente: la función Sum, presente en las líneas diez y dieciséis de este código 02, sigue devolviendo el mismo tipo de valor. Observa que estamos haciendo uso de una conversión explícita en la línea 19, esto para que el compilador no se queje de que estamos usando tipos diferentes.

Pero el detalle ahora es el siguiente: nota que la diferencia entre la función Sum de la línea diez y la de la línea dieciséis es el tipo del primer argumento que será recibido por ella. Este tipo de cosa suele hacer un lío en la cabeza de mucha gente, ya que, a primera vista, no tiene sentido que usemos un tipo de 4 bytes para la función de la línea diez y un tipo de 1 byte para la función de la línea dieciséis.

De hecho, en este ejemplo que estamos usando, esto es completamente innecesario. Sin embargo, puede que el programador, por cualquier motivo, trabaje internamente en las funciones de forma que la función de la línea dieciséis, de hecho, necesite recibir un tipo char, ya que el tipo int puede no ser adecuado. Recordando que existe una forma de resolver esto de otra manera.

No obstante, esto se verá en otro artículo. Aquí, estamos considerando que tú no sepas cómo hacer tal cosa, así que decides hacerlo como se muestra en el código 02.

Pregunta: ¿Esto está mal? No, mi estimado lector, crear, escribir e implementar un código como se ve en el código 02 no está mal, simplemente demuestra que aún tienes y necesitas aprender un poco más sobre cómo programar en MQL5. Pero, definitivamente, no está mal.

Bien, estas fueron las formas simples de sobrecarga. Existe otra, donde, en lugar de declarar parámetros de tipos diferentes, usamos un número diferente de parámetros. Este caso tal vez pueda ser el más común, dado que, a diferencia de C y C++, donde podemos implementar un número prácticamente infinito de parámetros sin cambiar la declaración de la función o procedimiento, aquí en MQL5 no podemos hacer esto. Bueno, esto en prueba, pues existe una forma de hacerlo. Mostré cómo en un artículo anterior, aunque eso fue solo un aperitivo de lo que realmente podemos hacer cuando ciertos recursos hayan sido explicados.

Pero, nuevamente, vamos a considerar que tú, mi estimado lector, estés de hecho aprendiendo y quieras aprender de la manera correcta. Entonces, ¿cómo sería esta otra forma de sobrecarga? Bien, puede verse justo abajo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(Sum(10, 25));
07.     Print(Sum(-10, 25, 4));
08. }
09. //+------------------------------------------------------------------+
10. long Sum(long arg1, long arg2)
11. {
12.     Print(__FUNCTION__, "::", __LINE__);
13.     return arg1 + arg2;
14. }
15. //+------------------------------------------------------------------+
16. long Sum(long arg1, long arg2, long arg3)
17. {
18.     Print(__FUNCTION__, "::", __LINE__);
19.     return arg1 + arg2 + arg3;
20. }
21. //+------------------------------------------------------------------+

Código 03

Pues bien, en este caso, el resultado sería lo que puedes observar en la imagen que viene a continuación.

Imagen 02

Hasta donde ya he podido observar, gran parte de los principiantes tiene más facilidad para entender este tipo de código 03 que los demás, ya que parece más simple entender cuál sería la función o procedimiento que sería llamado en cada caso. Muchos no consideran este tipo de implementación, vista en el código 03, como un tipo de sobrecarga. Sin embargo, en la literatura, muchos autores, de hecho, consideran esto un tipo de sobrecarga, ya que el nombre de la función sigue siendo el mismo.

Vale, creo que ha quedado claro qué sería o no una sobrecarga. Pero, aún queda una pregunta: ¿Por qué funciona y cómo el compilador consigue distinguir entre una y otra, solo por el hecho de que estamos utilizando tipos diferentes? Esto, aparentemente, no tiene mucho sentido, no a primera vista.

De hecho, mi estimado lector, esto no tiene mucho sentido, dado que, cuando utilizamos una función, usamos el nombre con el que la misma fue declarada, y no algo distinto a esto. Pero entonces, ¿por qué funciona? El motivo es que, para que un código realmente pueda convertirse en ejecutable, es necesario que el compilador consiga entender cómo direccionar adecuadamente el flujo de ejecución. Y, cuando la sobrecarga, en este caso de funciones y procedimientos, es utilizada, el compilador va a crear un nombre interno único. Digo interno, pues tú no sabes exactamente cómo será hecho esto, aunque, en general, se hace usando algunas reglas simples.

Por ejemplo: mirando el código 03, en la línea diez, el compilador puede llamar a esa función Sum como Sum_long_long; mientras que a la función de la línea dieciséis, puede llamarla Sum_long_long_long. Observa que, aunque aparentemente simple, esto ya hace mucha diferencia, pues sería como si estuviéramos creando una función con un nombre único.

Lo mismo se aplica al código 02. Allí, la función de la línea diez puede estar siendo llamada Sum_int_ulong; mientras que la de la línea dieciséis, Sum_char_ulong. Nota que, ahora, la cosa empieza a tener más sentido, y de ahí el hecho de que el compilador pueda entender hacia dónde debe ser dirigido el flujo de ejecución en un momento dado.

Una observación importante: aquí, estoy usando esta nomenclatura solo por motivos didácticos, ya que, dependiendo de la implementación y de la forma en que los desarrolladores del compilador lo hayan concebido, esta nomenclatura puede ser totalmente diferente. Pero entiende que, internamente, el compilador hará algo parecido a esto.

Perfecto, estamos prácticamente terminando lo que sería el uso de la sobrecarga. Solo faltan dos ejemplos más que, a mi parecer, pueden ser interesantes de mostrar. El primero se ve justo abajo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     int v = -5;
07. 
08.     Sum(v, Sum(10, 25));
09.     Print(v);
10. }
11. //+------------------------------------------------------------------+
12. long Sum(long arg1, long arg2)
13. {
14.     Print(__FUNCTION__, "::", __LINE__);
15.     return arg1 + arg2;
16. }
17. //+------------------------------------------------------------------+
18. void Sum(int &arg1, long arg2)
19. {
20.     Print(__FUNCTION__, "::", __LINE__);
21.     
22.     arg1 += (int)arg2;
23. }
24. //+------------------------------------------------------------------+

Código 04

En este caso, tenemos la posibilidad de usar una función siendo sobrecargada junto con un procedimiento. Nota que los nombres son iguales, pero, debido a la cuestión de tipos, podemos tener el flujo siendo desviado en una u otra dirección. Es importante notar que, dependiendo de la manera en que este código 04 haya sido implementado, esto cuando nos referimos a los tipos de argumentos utilizados, así como a la forma de estructurar el código, puede presentar un resultado u otro. Esto por el simple hecho de que hayamos modificado algún mínimo detalle en las declaraciones, tanto de tipo como en la forma en que la línea ocho está siendo concebida.

Pues observa el siguiente hecho: aunque la línea ocho aparentemente se refiera a la función presente en la línea 12, el hecho de que estemos utilizando una variable en el primer argumento hace que tengamos la intención de llamar a la línea 18. Sin embargo, si el tipo declarado en la línea ocho no es compatible con el tipo esperado en la línea 18, podríamos, de hecho, nunca llamar a la línea 18, siendo todo hecho dentro de la línea 12. Por esta razón, es aconsejable no utilizar la sobrecarga de funciones y procedimientos de forma indebida o sin el debido cuidado, dado que podemos obtener resultados bastante conflictivos con los inicialmente esperados.

Sin embargo, de la forma en que el código 04 se encuentra, al ejecutarlo, visualizaremos el resultado que puede verse en la imagen a continuación.

Imagen 03

Nuevamente, este tipo de respuesta solo ocurrió porque los tipos coincidieron perfectamente bien, y el compilador consiguió comprender cuál era nuestra intención. No obstante, si algún programador, antes de estudiar y entender el código, decide que no quiere usar tipos long en su código, ya que es de 64 bits, y decide usar solo tipo int, por ser de 32 bits, observa lo que ocurrirá cuando tales cambios sean realizados. El mismo código 04 fue modificado, como se describió, y se convirtió en el código 05, que puede verse a continuación.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     int v = -5;
07. 
08.     Sum(v, Sum(10, 25));
09.     Print(v);
10. }
11. //+------------------------------------------------------------------+
12. int Sum(int arg1, int arg2)
13. {
14.     Print(__FUNCTION__, "::", __LINE__);
15.     return arg1 + arg2;
16. }
17. //+------------------------------------------------------------------+
18. void Sum(int &arg1, int arg2)
19. {
20.     Print(__FUNCTION__, "::", __LINE__);
21.     
22.     arg1 += (int)arg2;
23. }
24. //+------------------------------------------------------------------+

Código 05

Observa que se hizo un cambio muy inocente y sin mucha intención de causar problema, pero, al intentar crear el ejecutable, resulta que el compilador dice no entender lo que está siendo implementado, ya que el mensaje visto en la salida del compilador se muestra justo abajo.

Imagen 04

O sea, un intento totalmente inocente de cambiar el código por algo que el programador consideraba más adecuado terminó haciendo que el código fuera completamente incomprendido, ya que el compilador no sabe si debe ir a la línea 12 o a la línea 18 cuando la línea ocho tenga que ser ejecutada. Sin embargo, quiero que tú, mi estimado lector, entiendas una cosa aquí: el error NO ESTÁ EN LA LÍNEA OCHO. El error, en realidad, está en el hecho de que tenemos dos llamadas que, a entender del compilador, son exactamente iguales. El programador, por tener poca experiencia, enseguida imaginará que el problema está en la línea ocho, cuando en realidad está en la línea 12 o en la línea 18, como se explicó anteriormente, ya que el compilador puede estar creando un nombre interno único para intentar generar el ejecutable final.

Este tipo de abordaje, que aquí parece ser simple de resolver, puede ser extremadamente complicado en la práctica, esto porque una llamada puede estar en un archivo de encabezado, mientras que la otra puede estar en otro archivo de encabezado que puede no tener absolutamente nada que ver con el primero, lo que hace que la cosa sea aún más complicada y confusa.

Y, como último ejemplo, veamos otro caso donde se está utilizando la sobrecarga. Este se muestra en el código justo abajo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     long v = -16,
07.          m[];
08.     bool b;
09.     
10.     Add(m, Sum(10, 25));
11.     Print("Return: ", b = Sum(v, m));
12.     if (b) Print("Value: ", v);
13.     ArrayFree(m);
14. }
15. //+------------------------------------------------------------------+
16. void Add(long &arg[], long value)
17. {
18.     ArrayResize(arg, arg.Size() + 1);
19.     arg[arg.Size() - 1] = value;
20. }
21. //+------------------------------------------------------------------+
22. long Sum(long arg1, long arg2)
23. {
24.     Print(__FUNCTION__, "::", __LINE__);
25.     return arg1 + arg2;
26. }
27. //+------------------------------------------------------------------+
28. bool Sum(long &arg1, const long &arg2[])
29. {
30.     Print(__FUNCTION__, "::", __LINE__);
31. 
32.     if (arg2.Size() == 0)
33.         return false;
34. 
35.     for (uchar c = 0; c < arg2.Size(); c++)
36.         arg1 += arg2[c];
37.     
38.     return true;
39. }
40. //+------------------------------------------------------------------+

Código 06

Este de aquí es, de hecho, un caso muy interesante y que tiene muchas implicaciones prácticas, ya que no es raro, al menos aquí en MQL5, cuyo objetivo es crear mecanismos para generar interpretación gráfica de precios y operaciones, que implementemos un código cuyo propósito u objetivo principal sea efectuar algún tipo de factorización con múltiples datos de cotización. Normalmente, este tipo de factorización está de alguna manera vinculado al desarrollo de algún indicador específico o algún modelo de negociación que será utilizado en un Asesor Experto, esto con el fin de generar alguna indicación gráfica plausible y llamar la atención del operador o usuario de la plataforma MetaTrader 5 para abrir o cerrar alguna posición o, como mínimo, estar atento a algún movimiento específico que pueda ocurrir en algunos instantes.

Sé que muchos, principalmente los principiantes, se sienten ansiosos por crear algo y ver eso ejecutándose. Sin embargo, antes incluso de que podamos hacer esto, es necesario entender precisamente este tipo de cosas que estamos viendo en estos artículos actuales, donde el material es más básico y tiene como objetivo, precisamente, crear una base sólida para que podamos trabajar después con algo más elaborado y enfocado en algún tipo de actividad específica. Como no quiero estar perdiendo mucho tiempo explicando detalles simples en el futuro, estoy creando esta base de conocimiento ahora. Así, tú, mi estimado lector, podrás adaptar o incluso mejorar lo que será visto en los artículos con material más específico, no solo los míos, sino de cualquier otro programador del cual quieras usar parte de la idea o del código presentado.

Pues bien, en este código 06, tenemos exactamente un ejemplo de sobrecarga, donde, en ocasiones, utilizaremos un valor discreto de manera bastante interesante, y en otras, utilizaremos un conjunto de valores que estarán presentes en un array de datos. Sin embargo, a pesar de esta aparente simplicidad, no es raro que tengamos problemas en los cálculos que están siendo realizados, esto debido a pequeñas fallas en la comprensión de ciertos conceptos básicos. Entre estas fallas, está el hecho de que, muchas veces, acabamos cometiendo el error de no prestar atención a los valores iniciales de los parámetros pasados a una función. Este tipo de cosa suele dar cierto trabajo para ser corregida, hasta que llegamos a darnos cuenta del motivo del fallo.

Pero este tipo de cosa es más fácil de entender en la práctica, y, conforme vayas ganando experiencia, será cada vez más difícil cometer tal error, aunque, cuando llegue a ocurrir, será debido a alguna distracción que hayas tenido durante la implementación.

Pero vamos a entender qué tenemos aquí en el código 06. Cuando ejecutamos este código, como se mostró arriba, tendrás el siguiente resultado, mostrado justo abajo.

Imagen 05

Ahora, entiende lo siguiente, mi estimado lector: como se dijo hace poco, no es raro que tengamos problemas en factorizaciones múltiples, esto debido a que estamos usando un número incorrecto de elementos en la factorización. Para evitar esto, dejamos de retornar el valor en la función y pasamos a retornar una indicación. Esta nos dirá si el valor factorizado debe o no ser aceptado. Entonces, en la línea 32, probamos este tipo de cosa. Nota que la función Sum aún así está siendo sobrecargada, ya que, en la línea 22, tenemos el mismo nombre que se le da a la función de la línea 28. Sin embargo, el hecho de que el valor retornado no tenga el mismo propósito no implica que la función no esté siendo sobrecargada.

Este tipo de cosa puede, muchas veces, ser confuso, aún más cuando miramos solo las líneas donde la función está siendo utilizada. Observa esto: al mirar las líneas diez y once, claramente notas que no tiene mucho sentido lo que estamos retornando allí. Por esto, siempre que tengas dudas respecto a cómo funciona un código, procura estudiar sus detalles. No imagines que, solo porque una función o procedimiento tiene el mismo nombre que otra función o procedimiento que ya conoces, ambas van a hacer y trabajar de la misma manera, pues no siempre es así como funcionan las cosas.

Y, para terminar, podemos hacer un pequeño cambio en el código 06. Este se muestra en el fragmento justo abajo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     long v = -16,
07.          m[];
08.     bool b;
09.     
10. //    Add(m, Sum(10, 25));
11.     Print("Return: ", b = Sum(v, m));
12.     if (b) Print("Value: ", v);
13.     ArrayFree(m);
14. }
15. //+------------------------------------------------------------------+
                   .
                   .
                   .

Fragmento 01

Nota que, en este fragmento, estoy eliminando una línea del código, convirtiéndola en un comentario; en este caso, es la línea diez. Pero este simple cambio, que podría implicar que no hayamos añadido un número adecuado de elementos para ser factorizados, hará que el resultado sea el que se muestra justo abajo.

Imagen 06

Experimenta hacer otros cambios en este código 06, con el fin de conseguir otros tipos de entendimientos, pues esto te ayudará bastante en el futuro.


Consideraciones finales

Este tal vez haya sido el artículo más confuso para ti, principiante, ya que aquí mostré que no siempre tendremos, en un mismo código, todas las funciones y procedimientos con nombres exclusivos. Podemos, sí, tener funciones y procedimientos con un mismo nombre, y esto se conoce como sobrecarga. Aunque sea algo posible, debe tenerse cuidado al usar tal práctica, ya que esto, muchas veces, vuelve el código tanto confuso para implementar como también difícil de corregir.

Espero que este artículo sirva de aclaración, haciéndote más cuidadoso respecto a no simplemente imaginar que una función o procedimiento ya conocidos tendrá o deberá tener el mismo comportamiento que otro procedimiento o función que esté siendo implementado haciendo uso de la sobrecarga.

En el anexo, dejaré parte de los códigos vistos en este artículo. Procura estudiar este material, modificando los códigos del anexo de forma que entiendas cómo la sobrecarga puede afectar tanto la comprensión del código como posibles fallos que pueden ocurrir debido al mal uso de la sobrecarga. Es mejor aprender a lidiar con fallos cuando los mecanismos son más simples que intentar lidiar con un fallo en algo más complicado. Entonces, estudia esta cuestión de la sobrecarga en este momento, donde todo es más simple, pues, a medida que avancemos, las cosas se volverán aún más complejas.

Traducción del portugués realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/pt/articles/15642

Archivos adjuntos |
Anexo.zip (1.98 KB)
Aliaksandr Kazunka
Aliaksandr Kazunka | 27 jun 2025 en 21:36
en las nuevas versiones del terminal dos funciones con el mismo nombre generan un error de compilación
Creación de un Asesor Experto MQL5 basado en la estrategia PIRANHA utilizando las Bandas de Bollinger Creación de un Asesor Experto MQL5 basado en la estrategia PIRANHA utilizando las Bandas de Bollinger
En este artículo, creamos un Asesor Experto (Expert Advisor, EA) en MQL5 basado en la estrategia PIRANHA, utilizando Bandas de Bollinger para mejorar la efectividad comercial. Discutimos los principios clave de la estrategia, la implementación de la codificación y los métodos de prueba y optimización. Este conocimiento le permitirá implementar el EA en sus escenarios comerciales de manera efectiva.
Del básico al intermedio: Punto flotante Del básico al intermedio: Punto flotante
Este artículo es una breve introducción a lo que sería el punto flotante. Como este contenido es muy complicado, te aconsejo leer con calma y atención. No esperes dominar el sistema de punto flotante de manera rápida. El mismo solo se domina con el tiempo y la experiencia de uso. Pero este artículo te ayudará a entender por qué, a veces, tu aplicación reporta un resultado diferente del esperado originalmente. El contenido expuesto aquí tiene un propósito puramente didáctico. En ningún caso debe considerarse una aplicación cuya finalidad no sea el aprendizaje y el estudio de los conceptos mostrados.
Simulación de mercado (Parte 01): Orden cruzada (I) Simulación de mercado (Parte 01): Orden cruzada (I)
A partir de este artículo, iniciaremos la segunda fase, que tratará la cuestión del sistema de repetición/simulación de mercado. Entonces, comenzaremos mostrando una posible solución para el cruce de órdenes. Esta solución que presentaré no es definitiva, sino una propuesta para el problema que aún será necesario abordar próximamente.
Creación de un Panel de administración de operaciones en MQL5 (Parte III): Ampliación de las clases incorporadas para la gestión de temas (II) Creación de un Panel de administración de operaciones en MQL5 (Parte III): Ampliación de las clases incorporadas para la gestión de temas (II)
En este artículo, ampliaremos cuidadosamente la biblioteca Dialog existente para incorporar la lógica de gestión de temas. Además, integraremos métodos para cambiar de tema en las clases CDialog, CEdit y CButton utilizadas en nuestro proyecto de Panel de administración. Continúe leyendo para obtener perspectivas más reveladoras.