Скачать MetaTrader 5

Перегрузка функций

Обычно в названии функции стремятся отобразить ее основное назначение. Читабельные программы, как правило, содержат разнообразные и грамотно подобранные идентификаторы. Иногда различные функции используются для одних и тех же целей. Например, рассмотрим функцию, которая вычисляет среднее значение массива чисел двойной точности, и такую же функцию, но оперирующую массивом целых чисел. И ту, и другую удобно назвать AverageFromArray:

//+------------------------------------------------------------------+
//| вычисление среднего для массива типа double                      |
//+------------------------------------------------------------------+
double AverageFromArray(const double & array[],int size)
  { 
   if(size<=0) return 0.0;
   double sum=0.0;
   double aver;
//---
   for(int i=0;i<size;i++)
     {
      sum+=array[i];    // сложение для double
     }
   aver=sum/size;       // просто делим сумму на количество
//---
   Print("Вычисление среднего для массива типа double");
   return aver;
  }
//+------------------------------------------------------------------+
//| вычисление среднего для массива типа int                         |
//+------------------------------------------------------------------+
double AverageFromArray(const int & array[],int size)
  {
   if(size<=0) return 0.0;
   double aver=0.0;
   int sum=0;
//---
   for(int i=0;i<size;i++)
     {
      sum+=array[i];     // сложение для int
     }
   aver=(double)sum/size;// приведем сумму к типу double и разделим
//---
   Print("Вычисление среднего для массива типа int");
   return aver;
  }

Каждая функция содержит вывод сообщения посредством функции Print();

   Print("Вычисление среднего для массива типа int");

Компилятор выбирает нужную функцию в соответствии с типами аргументов и их количеством. Правило, по которому осуществляется этот выбор, называется алгоритмом соответствия сигнатуре. Под сигнатурой понимается список типов, который используется в объявлении функции.

Пример:

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   int    a[5]={1,2,3,4,5};
   double b[5]={1.1,2.2,3.3,4.4,5.5};
   double int_aver=AverageFromArray(a,5);
   double double_aver=AverageFromArray(b,5);
   Print("int_aver = ",int_aver,"   double_aver = ",double_aver);
  }
//--- Результат работы скрипта
// Вычисление среднего для массива типа int
// Вычисление среднего для массива типа double
// int_aver= 3.00000000    double_aver= 3.30000000

Перегрузка функций – это создание нескольких функций с одним именем, но с разными параметрами. Это означает, что в перегружаемых вариантах функции разным должно быть количество аргументов и/или их тип. Выбор конкретного варианта функции зависит от типов аргументов, полученных функцией. Конкретная функция выбирается в зависимости от соответствия списка аргументов при вызове функции списку параметров в объявлении функции.

Когда вызывается перегруженная функция, компилятор должен иметь алгоритм для выбора надлежащей функции. Алгоритм, который выполняет этот выбор, зависит от того, преобразования какого типа присутствуют. Наилучшее соответствие должно быть уникальным. Найденная функция должна быть наилучшим выбором среди остальных вариантов хотя бы по одному аргументу, и, в то же время, по остальным аргументам она должна подходить не хуже остальных.

Ниже приведен алгоритм соответствия для каждого аргумента.

Алгоритм выбора перегруженной функции

  1. Использовать строгое соответствие (если это возможно).
  2. Попробовать стандартное повышение типа.
  3. Попробовать стандартное преобразование типа.

Стандартное повышение типа лучше, чем остальные стандартные преобразования. Повышение - это преобразование float в double, а также bool, char, short или enum в int. Кроме того, к стандартным преобразованиям относятся преобразования массивов похожих целых типов. Похожими типами являются: bool, char, uchar, так как все три типа являются однобайтовыми целыми; двубайтовые целые short и ushort; 4-байтовые целые int, uint и color; long, ulong и datetime.

Несомненно, строгое соответствие является наилучшим. Для достижения такого соответствия могут использоваться приведения. Компилятор не справится с двусмысленной ситуацией. Поэтому не следует полагаться на тонкие различия в типах и неявные преобразования, которые делают перегруженную функцию неясной.

Если вы сомневаетесь, используйте явные преобразования для обеспечения строгого соответствия.

Примеры перегруженных функций в MQL5 вы можете увидеть на примере функций ArrayInitialize().

Правила перегрузки функций применимы к перегрузке методов классов.

 

Перегрузка системных функций допускается, но при этом следует следить за тем, чтобы компилятор точно мог выбрать нужную функцию. Для примера, мы можем перегрузить системную функцию MathMax() 4-мя различными способами, но только два варианта будут корректными.

Пример:

// 1. перегрузка допустима - функция отличается от встроенной в язык MathMax() по количеству параметров
double MathMax(double a,double b,double c);
 
// 2. перегрузка недопустима!
// количество параметров разное, но последний имеет значение по умолчанию
// это приводит к сокрытию системной функции при вызове, что недопустимо
double MathMax(double a,double b,double c=DBL_MIN);
 
// 3. перегрузка допустима - нормальная перегрузка по типу параметров a и b
int MathMax(int a,int b);
 
// 4. перегрузка недопустима!
// количество и тип параметров не отличается от исходной double MathMax(double a,double b)
int MathMax(double a,double b);

Смотри также

Перегрузка, Виртуальные функции, Полиморфизм


Обновлено: 2015.12.03