Учёба. Классы. Нужна помощь. - страница 15

 
Alexey Viktorov #:

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

В классе CTrade есть такие виртуальные функции

И мне кажется они никак не используются, если работать через этот класс. 

В других местах есть другие. Вот и хочется понять как это работает.

Ну... скажем...

Смотри, тебе надо отслеживать некоторые ордера, которые ты отсылаешь на сервер (скажем, для статистики). 

У тебя уже есть большой эксперт, с всяким анализом, условиями, кучей кода. Разбираться в нём, где можно взять статистику - сложно.

Но в этом эксперте, есть объект класса CTrade, у которого ты вызываешь метод SendOrder(). Метод виртуальный - а значит, тебе совершенно не надо смотреть весь код эксперта. Ты просто описываешь объект:

class CStatTrade: public CTrade

{

protected:

// Здесь переменные для сбора статистики.


public:

...

virtual bool OrderSend(const MqlTradeRequest &request,MqlTradeResult &result)

{

// Здесь ты собираешь стистику, и запоминаешь в protected-переменных класса CStatTrade

// А потом - вызываешь метод базового класса

return( CTrade::OrderSend(request,&result))

};

...

} // конец класса СStatTrade


И далее, в коде эксперта создаёшь вместо объекта CTrade - объект CMyTrade.

Все его методы пронаследованы, и он будет нормально работать. 

А метод SendOrder - будет дополнительно ещё и собирать твою статистику. И потом, где надо - ты из созданного объекта CMyTrade - сможешь вытащить собранную статистику.

ВАЖНО!!!

В чем главная особенность виртуальной функции. При вызове SendOrder - у тебя есть две функции - базовая, и пронаследованная (и наследников может быть куча, с большой иерархией). И какая именно будет вызвана, определяется не в момент компиляции, а в момент создания объекта CTrade или CStatTrade. 

Именно в этом суть виртуальных функций - если функции невиртуальны, то какая именно будет вызвана - решается в момент компиляции. А если виртуальны - то это определяется в момент создания объекта, у которого эта виртуальная функция будет вызвана. Это называется "позднее связывание"

 
Vladislav Boyko #:

Самое интересное как раз-таки осталось за кадром.

Что внутри? switch? dynamic_cast?

И это тоже. Макрос  CONVERT_CONST_OBJECT_WITH_CHECK как раз проверяет тип объекта, с учётом того, что это не просто CObject, а CMyObject, там проверяется внутренний ID типа:

CMyObject* _PerformObjectConvertWithCheck(CMyObject* pmoObject,EMyObjectTypes motType)
{
   ASSERT_MYPOINTER(pmoObject);                    // проверим указатель
   ASSERT(pmoObject.CheckType(motType) == true);   // проверим внутренний ID типа объекта
   
   return(pmoObject);
};

const CMyObject* _PerformConstObjectConvertWithCheck(const CMyObject* pmoObject,EMyObjectTypes motType)
{
   ASSERT_MYPOINTER(pmoObject);                    // проверим указатель
   ASSERT(pmoObject.CheckType(motType) == true);   // проверим внутренний ID типа объекта
   
   return(pmoObject);
};

#define CONVERT_OBJECT_WITH_CHECK(objFrom,typeTo,checkType) ((typeTo*)_PerformObjectConvertWithCheck(objFrom,checkType))
#define CONVERT_CONST_OBJECT_WITH_CHECK(objFrom,typeTo,checkType) ((typeTo*)_PerformConstObjectConvertWithCheck(objFrom,checkType))
Макросы ASSERT - в релизной версии пустые. Дебаг-версию - прикрпеляю. 
Файлы:
AssertD.mqh  12 kb
 
Georgiy Merts #:

В чем главная особенность виртуальной функции. При вызове SendOrder - у тебя есть две функции - базовая, и пронаследованная. И какая именно будет вызвана, определяется не в момент компиляции, а в момент создания объекта CTrade или CStatTrade. 

Именно в этом суть виртуальных функций - если функции невиртуальны, то какая именно будет вызвана - реашется в момент компиляции. А если виртуальны - то это определяется в момент создания объекта, у которого эта виртуальная функция будет вызвана. 

Чуть дополню.

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

 
Sergey Gridnev #:

Вот ещё что забыл указать. Если бы метод Compare не был виртуальным, то CArray из функции Sort вызвал бы метод класса CObject.

Вот-вот! 

Алексей, как раз про это я и написал в прошлом сообщении!

Если бы метод Compare() был бы невиртуальным, то какую из функций вызывать, определялось бы в момент компиляции. А там у нас указатель на класс CObject - функция именно этого объекта и была бы создана. 

А вот если эта функция виртуальна, то какая именно функция будет вызвана - в момент компиляции ещё неизвестно. Это будет известно только тогда, когда ты будешь создавать объекты, пронаследованные от CObject. И именно функции этих создаваемых объектов будут вызываться. 

 
Georgiy Merts #:

Ну... скажем...

Смотри, тебе надо отслеживать некоторые ордера, которые ты отсылаешь на сервер (скажем, для статистики). 

У тебя уже есть большой эксперт, с всяким анализом, условиями, кучей кода. Разбираться в нём, где можно взять статистику - сложно.

Но в этом эксперте, есть объект класса CTrade, у которого ты вызываешь метод SendOrder(). Метод виртуальный - а значит, тебе совершенно не надо смотреть весь код эксперта. Ты просто описываешь объект:

class CStatTrade: public CTrade

{

protected:

// Здесь переменные для сбора статистики.


public:

...

virtual bool OrderSend(const MqlTradeRequest &request,MqlTradeResult &result)

{

// Здесь ты собираешь стистику, и запоминаешь в protected-переменных класса CStatTrade

// А потом - вызываешь метод базового класса

return( CTrade::OrderSend(request,&result))

};

...

} // конец класса СStatTrade


И далее, в коде эксперта создаёшь вместо объекта CTrade - объект CMyTrade.

Все его методы пронаследованы, и он будет нормально работать. 

А метод SendOrder - будет дополнительно ещё и собирать твою статистику. И потом, где надо - ты из созданного объекта CMyTrade - сможешь вытащить собранную статистику.

ВАЖНО!!!

В чем главная особенность виртуальной функции. При вызове SendOrder - у тебя есть две функции - базовая, и пронаследованная (и наследников может быть куча, с большой иерархией). И какая именно будет вызвана, определяется не в момент компиляции, а в момент создания объекта CTrade или CStatTrade. 

Именно в этом суть виртуальных функций - если функции невиртуальны, то какая именно будет вызвана - реашется в момент компиляции. А если виртуальны - то это определяется в момент создания объекта, у которого эта виртуальная функция будет вызвана. Это называется "позднее связывание"

Откуда эти функции?

Видимо это не для моих мозгов. Но всё-же я постараюсь понять это.

 
Alexey Viktorov #:

Но всё-же я постараюсь понять это.

Виртуальные методы полезны только при использовании указателей. Если указатели не используются, virtual не пригодится.


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

И если используются указатели, то можно собаку обобщить, сказав всем, что это Животное (указатель). Но при этом оно будет лаять.


В итоге можно, например, наплодить (создать объекты) собак, кошек и баранов. Затем загнать их в один одинаковый загон Животных (массив указателей на Животных). И, вроде, в массиве все Животные, но звук будет каждый издавать свой: лаять, мяукать, блеять.

 
Sergey Gridnev #:

Вот ещё что забыл указать. Если бы метод Compare не был виртуальным, то CArray из функции Sort вызвал бы метод класса CObject.
Georgiy Merts #
:

Вот-вот! 

Алексей, как раз про это я и написал в прошлом сообщении!

Если бы метод Compare() был бы невиртуальным, то какую из функций вызывать, определялось бы в момент компиляции. А там у нас указатель на класс CObject - функция именно этого объекта и была бы создана. 

А вот если эта функция виртуальна, то какая именно функция будет вызвана - в момент компиляции ещё неизвестно. Это будет известно только тогда, когда ты будешь создавать объекты, пронаследованные от CObject. И именно функции этих создаваемых объектов будут вызываться. 

То-есть функция в потомке просто заменяет функцию родителя?

Если так, то зачем всё это городить если простая функция будет работать так-же… В чём прикол? В чём полезность виртуальности?

Ну в том примере, что привёл я, это не я писал, там более-менее понятно. Внутри классов СArray и  СArrayObj неоднократно вызывается метод Compare и в этом случае понятно будет замена. А вот объяснения с классом CTrade совсем не догоняю.

 
fxsaber #:

Виртуальные методы полезны только при использовании указателей. Если указатели не используются, virtual не пригодится.


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

И если используются указатели, то можно собаку обобщить, сказав всем, что это Животное (указатель). Но при этом оно будет лаять.


В итоге можно, например, наплодить (создать объекты) собак, кошек и баранов. Затем загнать их в один одинаковый загон Животных (массив указателей на Животных). И, вроде, в массиве все Животные, но звук будет каждый издавать свой: лаять, мяукать, блеять.

Вот это понятней

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Интересное и Юмор

Alexey Viktorov, 2024.11.01 07:44

Доходчиво про объекты и указатели:

«Вообще, создание объектов через new - это как слепил шарик из какахи (чтобы соседу 1 на коврик положить потом) и кинул в мешок чтоб не воняло. Потом слепил второй шарик (для соседа 2) и тоже его в мешок... потом третий, четвёртый, десятый ... ну.. сколько соседей обрадовать хочешь - столько шариков в мешок.
И когда наступает час Ч ты понимаешь, что какахи не пронумерованы, и ты не знаешь какая принадлежит какому соседу... Засада, да?
Так вот - указатели - это верёвочки с бирочками с номерами соседа 1, 2, 3, 100 ... они привязаны к шарикам, которые в мешке (памяти), а второй конец с бирочками - у тебя в руках (в списке). Теперь по номеру соседа ты тянешь за нужную верёвочку (указатель) и достаёшь из мешка (памяти) нужную какаху (объект), получая к нему доступ и делая с ним нужные делишки.»


 
Alexey Viktorov #:

Вот это понятней

Написал про виртуальные функции, а не про указатели.

 
fxsaber #:

Написал про виртуальные функции, а не про указатели.

Вот это полезно и понятно. За это спасибо.

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Учёба. Классы. Нужна помощь.

fxsaber, 2024.12.16 10:30

Виртуальные методы полезны только при использовании указателей. Если указатели не используются, virtual не пригодится.