ООП. Вопросы применения - страница 4

 
Yedelkin:

Вопрос. Можно ли после объявления в родительском классе виртуальной функции с определённым набором параметров и их типов изменять  в классах-потомках количество и типы параметров у соответствующих виртуальных функций?

С одной стороны, в Справочнике говорится, что "виртуальная функция может замещаться в производном классе. Выбор того, какое определение функции вызвать для виртуальной функции, происходит динамически (на этапе выполнения). Типичный случай – когда базовый класс содержит, а производные классы имеют свои версии этой функции". С другой стороны, приведённые в Справочнике примеры касаются случаев, когда у виртуальных функций различаются тела определения функций, а не заголовки определения функций.

 

На сколько помню можно. Но нужно абсолютно жоское различие в типах и количестве параметров.

Также следует быть осторожным с тими передаваемых значений и дефаултными значениями.

Для простоты приведу примеры.

Такой вариант прокатит

boll MyFunction(int Param);
boll MyFunction(int Param1,int Param2);

Такой нет (верней может ипрокатит, но при багах и определенных оговорках)

//Ели второй параметр будет упущен, то компилятор может и не "понять" смысла всего задуманного
boll MyFunction(int Param);
boll MyFunction(int Param1,int Param2 = 0);
//Так тоже может не прокатить по причине совпадения типов у второго параметра
boll MyFunction(int Param1,color Param2);
boll MyFunction(int Param1,int Param2);

Точно такая же фигня творится если происходит ПЕРЕЗАГРУЗКА методов внутри класса.

 
mql5:
Только точная копия определения, за исключением параметров по умолчанию (умолчания могут отличаться, но лучше это не использовать)
Вы имеете в виду "только точную копию заголовка определения"? Ведь определение функции включает в себя заголовок плюс тело. Тела в примерах точно различаются.
 

Interesting, как я понял, виртуализация функций и перегрузка функций - немного разные вещи. И вот mql5 говорит, что при виртуализации функций должна быть жёсткая копия заголовка функции(параметры по умолчанию в расчет не беру). 

 
Yedelkin:

Interesting, как я понял, виртуализация функций и перегрузка функций - немного разные вещи. И вот mql5 говорит, что при виртуализации функций должна быть жёсткая копия заголовка функции(параметры по умолчанию в расчет не беру).

> Вопрос. Можно ли после объявления в родительском классе виртуальной функции с определённым набором параметров и их типов изменять  в классах-потомках количество и типы параметров у соответствующих виртуальных функций?

Если я все правильно понимаю то потомок должен перегрузить функционал предка.

Честно говоря я не помню делал или нет подобные вещи с виртуальными (кажется делал), но про перегрузку утверждение верно - сам наступил однажды на эти грабли.

PS

Если все делать правильно, то как я понимаю, количество параметров можно как увеличивать так и уменьшать. Сложности будут если если количество параметров останется прежним, но изменятся их типы...

 

В общем, набросал вот такой пример:

class C_A             //родительский класс
{
 public:
 virtual double function(double a1, double a2, double a3) { return; }
}
class C_B : public C_A
{
 public:
 virtual double function(double a1, double a2, double a3) { return(a1);   }
}
class C_C : public C_A
{
 public:      
 virtual double function(double a1, double a2, double a3) { return(a2);   }
        double function(double a1, double a2)           { return(a1+a2); }
}
//где-то в программе объявляем указатель
C_A  *pointer;
int random=rand()%2;
   switch(random)
     {
      case 0: pointer=new C_B; break;
      case 1: pointer=new C_C; break;
     }

//вызываем виртуальный метод
   if(pointer!=NULL)
     {
      pointer.function(a1,a2,a3);
     }

Получается, что независимо от того, перегружен или нет метод function в классе С_С, виртуальная функция может быть вызвана только с тремя параметрами - pointer.function(a1,a2,a3). Соответственно, до двухпараметного метода из класса С_С программа при вызове виртуальных функций никогда не доберётся. Правильно? 

 
Yedelkin:

В общем, набросал вот такой пример:

Получается, что независимо от того, перегружен или нет метод function в классе С_С, виртуальная функция может быть вызвана только с тремя параметрами - pointer.function(a1,a2,a3). Соответственно, до двухпараметного метода из класса С_С программа при вызове виртуальных функций никогда не доберётся. Правильно? 

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

От себя же добавлю что объявляя указатель базового класса вы тем самым строите "тонельный" проход к потомкам через базовый класс. Таким образом компилятор при таком вызове потомков будет видеть у потомков только функции объявленные в базовом классе. Если же вы (даже в пределах одной программы) объявите напрямую объект потомка то в нём будут доступны все функции.

class C_A             //родительский класс
{
 public:
 virtual double function(double a1, double a2, double a3) { return; }
}
class C_B : public C_A
{
 public:
 virtual double function(double a1, double a2, double a3) { return(a1);   }
}
class C_C : public C_A
{
 public:      
 virtual double function(double a1, double a2, double a3) { return(a2);   }
        double function(double a1, double a2)           { return(a1+a2); }
}
//где-то в программе объявляем указатель
C_A  *pointer;
int random=rand()%2;
   switch(random)
     {
      case 0: pointer=new C_B; break;
      case 1: pointer=new C_C; break;
//вызываем виртуальный метод
   if(pointer!=NULL)
     {
      pointer.function(a1,a2,a3);
     }
C_С  *new_pointer=new C_C;
      new_pointer.function(a1,a2);
 
Yedelkin:

В общем, набросал вот такой пример:

Получается, что независимо от того, перегружен или нет метод function в классе С_С, виртуальная функция может быть вызвана только с тремя параметрами - pointer.function(a1,a2,a3). Соответственно, до двухпараметного метода из класса С_С программа при вызове виртуальных функций никогда не доберётся. Правильно? 

Из собственного опыта могу порекомендовать так комплектовать код

double function(double a1, double a2)            {return(a1+a2);}
double function(double a1, double a2, double a3) {return(a2);}

А в качестве примера и развлечения можете посмотреть вложенный файл.

С указателями и new было вазиться не охота, поэтому просто объявил рабочий класс как переменную.

Советник по таймеру через равные промежутки времени генерирует случайное число 0/1 и в зависимости от результата выполняет одну из двух функций: MarketBuy / MarketSell.


Можно было при желании и вот так объявить

bool MarketBuy(string SymbolTitle,double LotSize,double TP = 0.0,double SL = 0.0);
bool MarketSell(string SymbolTitle,double LotSize,double TP = 0.0,double SL = 0.0);

Но тогда может баг вылезти по поводу конфликта с

bool MarketBuy(string SymbolTitle,double LotSize);
bool MarketSell(string SymbolTitle,double LotSize);


PS

Делал на скорую руку, поэтому могут быть определенные неточности.

Но в принципе основную идею понять можно.

Файлы:
Forum.mq5  18 kb
 

Спасибо огромное за ценные советы и указания! Обязательно воспользуюсь, только б времени хватило и на теорию, и на практику.

Interesting:

Из собственного опыта могу порекомендовать так комплектовать код

double function(double a1, double a2)            {return(a1+a2);}
double function(double a1, double a2, double a3) {return(a2);}
Почему именно так? В чём подводный камень кроется?
 
Yedelkin:

Почему именно так? В чём подводный камень кроется?

Когда-то были проблемы вроде с этим. Но какие сейчас и не вспомню.

В общем привык так.

Обычно разницы конечно нет, по крайней мере в моем примере пробовал местами менять, все прокатило...

 
Interesting:

Когда-то были проблемы вроде с этим. Но какие сейчас и не вспомню.

ОК, в любом случае - возьму на заметку.
Причина обращения: