Теперь объявляем функцию, в которую будем передавать указатель на нужный объект ( то ли CiOpen, то ли CiClose):
double GetResult(CSeries * psSeries)
{
GetData(psSeries);
return (m_dInnerData);
}
а кто чей потомок?
Если CSeries родитель, то вы должны перед вызовом GetData определить таки чье же оно.
и преобразовать его в зависимости от типа пришедшего psSeris
CiOpen * iop=psSeries;
GetData(iop);
GetData(icl);
А как определить принадлежность пришедшего psSeries в GetResult - к iOpen или iClose - можете придумать сами.
Благодарю за оперативный ответ
а кто чей потомок?
Ну, в Стандартной Библиотеке общий предок - это CSeries, а CiOpen и CiClose - потомки. Я этим же и пользуюсь. Собственно, хотел сделать что-то вроде паттерна "Посетитель" - чтобы можно было универсально доставать данные из любого объекта-наследника от CSeries.
Если CSeries родитель, то вы должны перед вызовом GetData определить таки чье же оно.
и преобразовать его в зависимости от типа пришедшего psSeris
CiOpen * iop=psSeries;
GetData(iop);
GetData(icl);
А как определить принадлежность psSeries к iOpen или iClose - можете придумать сами.
То есть, сам CiOpen или CiClose - "не знает", кто он такой, и какие функции ему принадлежат ? То есть, все, даже виртуальные функции должны быть известны уже на этапе компиляции ?
А в чем тогда виртуальность функции ? В примере из документации (с фигурами тетрис) вызывается m_shape.Draw() - причем, как я понимаю, сама переменная m_shape - как раз имеет тип предка, а вовсе не одного из потомков.
Я думал, что виртуальные функции тем и отличаются, что конкретная перегруженная функция определяется во время создания объекта - и дальше, несмотря на то, что указатель преобразовывается к указателю на предка, функция остается прежней. Значит, в MQL - так нельзя ?
Благодарю за оперативный ответ
Ну, в Стандартной Библиотеке общий предок - это CSeries, а CiOpen и CiClose - потомки. Я этим же и пользуюсь. Собственно, хотел сделать что-то вроде паттерна "Посетитель" - чтобы можно было универсально доставать данные из любого объекта-наследника от CSeries.
То есть, сам CiOpen или CiClose - "не знает", кто он такой, и какие функции ему принадлежат ? То есть, все, даже виртуальные функции должны быть известны уже на этапе компиляции ?
А в чем тогда виртуальность функции ? В примере из документации (с фигурами тетрис) вызывается m_shape.Draw() - причем, как я понимаю, сама переменная m_shape - как раз имеет тип предка, а вовсе не одного из потомков.
Я думал, что виртуальные функции тем и отличаются, что конкретная перегруженная функция определяется во время создания объекта - и дальше, несмотря на то, что указатель преобразовывается к указателю на предка, функция остается прежней. Значит, в MQL - так нельзя ?
Вы немного по разному интерпретируете виртуальность функций. Сравните даже Ваш пример и то, что Вы делаете:
1) пример.
Есть множество фигур (которые все наследники от Shape). у каждой есть метод draw(), который был и у предка. (метод функции!)
Теперь можно задать массив фигур Shape, запихнуть туда разные фигуры (фигуры-потомки) и для каждой вызвать ее метод draw
Это и есть виртуальность
2) ваша попытка
Есть два потомка (open и close) и две функции (с одинаковым названием), одна принимает объект класса open, вторая объект класса close.
При этом эти два класса имеют общего предка.
И вот вы вызываете для предка функцию. Вопрос какую из?
И вот вы вызываете для предка функцию. Вопрос какую из?
Ну, я думал - того объекта, который был создан. По крайней мере, на MSVC такая конструкция очень даже работает. Ведь виртуальность заключается в том, что при создании объекта, он обладает таблицей виртуальных функций, в которой хранятся указатели на функции объекта, и эта таблица живет во время всей жизни объекта. Указатель на объект можно привести к указателю на потомка, таблица функций от этого не изменится.
Значит, здесь - иначе.
Хорошо.
Задача была в том, чтобы легко добавлять и убирать индикаторы в роботе по мере необходимости.
Как я понял, надо сделать моих потомков от CiOpen и CiClose (назовем их СiMyOpen и СiMyClose, и от других нужных таймсерий и индикаторов), у всех определить метод PutDataTo(CStorage* pStorage).
И определить класс CStorage, в котором мои потомки будут сохранять свои данные.
После этого - определяем массив потомков, и у всех вызываем одну и ту же фукнцию PutDataTo(CStorage* pStorage), каждый потомок сам заполняет хранилище так, как он считает нужным.
А я дальше уже использую данные из этого хранилища.
Получается так ?
Но только у кого вызывать данный метод ? Ведь у CSeries его не было ! Не хотелось бы вносить изменения в станадартную библиотеку (добавив такой метод)
Ну, я думал - того объекта, который был создан. По крайней мере, на MSVC такая конструкция очень даже работает. Ведь виртуальность заключается в том, что при создании объекта, он обладает таблицей виртуальных функций, в которой хранятся указатели на функции объекта, и эта таблица живет во время всей жизни объекта. Указатель на объект можно привести к указателю на потомка, таблица функций от этого не изменится.
Значит, здесь - иначе.
Хорошо.
Задача была в том, чтобы легко добавлять и убирать индикаторы в роботе по мере необходимости.
Как я понял, надо сделать моих потомков от CiOpen и CiClose (назовем их СiMyOpen и СiMyClose, и от других нужных таймсерий и индикаторов), у всех определить метод PutDataTo(CStorage* pStorage).
И определить класс CStorage, в котором мои потомки будут сохранять свои данные.
После этого - определяем массив потомков, и у всех вызываем одну и ту же фукнцию PutDataTo(CStorage* pStorage), каждый потомок сам заполняет хранилище так, как он считает нужным.
А я дальше уже использую данные из этого хранилища.
Получается так ?
так. и это работает нормально.
но это совсем не то, о чем вы спросили вначале и показали участок кода с ошибкой.
так. и это работает нормально.
но это совсем не то, о чем вы спросили вначале и показали участок кода с ошибкой.
Ну... Моя цель - достичь желаемого, если я ошибся - меня поправят знающие люди (вот, кстати, спасибо за консультацию).
Остался вопрос - вот эту функцию PutDataTo(CStorage* pStorage) - у кого вызывать ? Ведь в массиве хранятся разнородные объекты, с общим предком CSeries, но у этого предка-то не было такой функции !
Похоже, не получается...
Ну... Моя цель - достичь желаемого, если я ошибся - меня поправят знающие люди (вот, кстати, спасибо за консультацию).
Остался вопрос - вот эту функцию PutDataTo(CStorage* pStorage) - у кого вызывать ? Ведь в массиве хранятся разнородные объекты, с общим предком CSeries, но у этого предка-то не было такой функции !
Похоже, не получается...
Если не хотите менять предка CSeries, то (так как нет множественного наследования) делайте класс-заглушку между ним и вашими классами в котором и объявите виртуальную функцию
Естественно в массиве храните объекты этого класса-заглушки уже, а не CSeries
Laryx:
Остался вопрос - вот эту функцию PutDataTo(CStorage* pStorage) - у кого вызывать ?
у всех.
Ведь в массиве хранятся разнородные объекты, с общим предком CSeries, но у этого предка-то не было такой функции !
При чем здесь вообще виртуальность и наследование?
Есть две равнозначные перегрузки функции. При передаче базового класса в качестве параметра компилятор не знает какую из них выбрать, поэтому затык, т.к. перегрузки точно совпадающей по типу аргументов нет.
Неоднозначность надо убирать руками.
ну так добавьте! в чем проблема то?
у всех.
ну так добавьте! в чем проблема то?
Проблема в том, что я не хочу изменять базовые классы Стандартной Библиотеки. Собственно, и TheXpert об этом уже сказал. Придется, как тут предложили, делать "класс-заглушку".
При чем здесь вообще виртуальность и наследование?
Есть две равнозначные перегрузки функции. При передаче базового класса в качестве параметра компилятор не знает какую из них выбрать,
Виртуальность при том, что компилятор вроде как и не должен знать, какую из функций выбирать. В этом же и состоит суть позднего связывания, что нужная функция выбирается не компилятором, на этапе сборки программы, а во время работы программы, в момент создания объекта.
Ну, так или иначе, мне главное было понять, как сделать желаемое. Разобрался. Всем премного благодарен за участие и рекомендации.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Друзья, помогите !
Проблема:
Пишу класс с использованием Стандартной Библиотеки, который будет доставать данные из индикаторов (в данном случае - таймсерии).
В классе объявлю две виртуальные функции:
virtual void GetData(CiOpen* poOpen);
virtual void GetData(CiClose* pcClose);
Каждая из этих функций берет данные из соответствующего объекта-таймсерии, и сохраняет во внутренней переменной.
Теперь объявляем функцию, в которую будем передавать указатель на нужный объект ( то ли CiOpen, то ли CiClose):
double GetResult(CSeries * psSeries)
{
GetData(psSeries);
return (m_dInnerData);
}
Однако, пишет ошибку "ambiguous call to overloaded function" .
Странно - я думал, в этом и заключается позднее связывание - что функции определяются в момент создания объекта, а выходит, что нам уже сейчас, во время компиляции надо знать, какой именно объект будет вызывать данную ВИРТУАЛЬНУЮ функцию. При этом если одну из функций убрать (скажем, оставить только одну функцию с CiOpen) - то все в порядке, несмотря на передачу указателя CSeries, вызывается правильная функция с объектом CiOpen.
Что-то я не вполне пойму концепцию виртуальных функций...
Интересно, что если объявить функцию
virtual void GetData(CSeries* pcClose)
То никаких проблем не возникает, однако, и никакой витуальности тоже - просто вызывается эта, последняя функция... А как же с виртуальностью ?