Виртуальные методы полезны только при использовании указателей. Если указатели не используются, virtual не пригодится.
Полно примеров для начинающих, где есть, например, множество Животное с виртуальной функцией звука от него. И есть его производные "подмножества": собаки, кошки и т.д. И у каждого из них своя реализация общей виртуальной функции звука: лай, мяуканье и т.д.
И если используются указатели, то можно собаку обобщить, сказав всем, что это Животное (указатель). Но при этом оно будет лаять.
В итоге можно, например, наплодить (создать объекты) собак, кошек и баранов. Затем загнать их в один одинаковый загон Животных (массив указателей на Животных). И, вроде, в массиве все Животные, но звук будет каждый издавать свой: лаять, мяукать, блеять.
В том, что с помощью виртуальных методов реализуется полиморфизм - один из столпов ООП. Вот представьте себе стадо (группу) зверей, о котором писали выше. Там есть кошки, собаки, бараны и т.д. Пусть берём в цикле каждое животное и просим, чтобы оно издало звук. Заранее мы не знаем, кто нам попадётся. Но у каждого есть свой виртуальный метод озвучивания. И на этапе выполнения программы (run-time) он должен сработать и правильно озвучить выбранное животное.
Полно примеров для начинающих, где есть, например, множество Животное с виртуальной функцией звука от него. И есть его производные "подмножества": собаки, кошки и т.д. И у каждого из них своя реализация общей виртуальной функции звука: лай, мяуканье и т.д.
И если используются указатели, то можно собаку обобщить, сказав всем, что это Животное (указатель). Но при этом оно будет лаять.
В итоге можно, например, наплодить (создать объекты) собак, кошек и баранов. Затем загнать их в один одинаковый загон Животных (массив указателей на Животных). И, вроде, в массиве все Животные, но звук будет каждый издавать свой: лаять, мяукать, блеять.
Гораздо сложнее придумать простой пример для виртуальных методов, когда использование реализации базового класса может быть уместным на ряду с ее заменой производными классами. Лично я не могу простой пример придумать для этого.
Кусок кода (см. вложение) для их вычисления привожу здесь, как пример реальной задачи, которая просто решается только через ООП.
Например, если захотеть посмотреть процитированный исходник, то там будет использоваться слово virtual. Но для его работоспособности этот virtual не нужен, т.к.
Виртуальные методы полезны только при использовании указателей. Если указатели не используются, virtual не пригодится.
Т.е. все будет работать через механизм перегрузки, если убрать virtual.
Однако, по какой-то причине virtual там написан. Причина в том, что потенциально в будущем возможна работа с этими объектами через указатели. И тогда механизм перегрузки будет давать совсем не тот эффект, что потребуется. Прописывание виртуальности определяет разработчик часто на основе просто опыта/интуиции. Опытные почти сразу видят, что может быть virtual и прописывают. Даже если пока не собираются это использовать. Примерно так и получилось с CTrade.
Гораздо сложнее придумать простой пример для виртуальных методов, когда использование реализации базового класса может быть уместным на ряду с ее заменой производными классами. Лично я не могу простой пример придумать для этого.
Может так случиться, что многие животные не издают звуков. Тогда базовая виртуальная функция звука животного - тишина. И нам нужно писать реализацию звука нового животного только тогда, когда мы знаем, как оно звучит. Не знаем - не прописываем. Т.е. удобно (код лаконичный), когда базовая виртуальная функция прописана.
Можно сделать и реализацию в базовом классе как метод по умолчанию. Например:
class CiAnimal
{
public:
virtualvoid Sound()
{
Print("silent");
}; // звук, который издает животное
};
//+------------------------------------------------------------------+//| Класс CCat наследуется от класса CiAnimal |//+------------------------------------------------------------------+class CCat : public CiAnimal
{
public:
CCat()
{
Print("Cat was born");
}
~CCat()
{
Print("Cat is dead");
}
void Sound() override
{
Print("meou");
}
};
//+------------------------------------------------------------------+//| Класс CDog наследуется от класса CiAnimal |//+------------------------------------------------------------------+class CDog : public CiAnimal
{
public:
CDog()
{
Print("Dog was born");
}
~CDog()
{
Print("Dog is dead");
}
void Sound() override
{
Print("guaf");
}
};
//+------------------------------------------------------------------+//| Класс CTurtle наследуется от класса CiAnimal |//+------------------------------------------------------------------+class CTurtle : public CiAnimal
{
public:
CTurtle()
{
Print("Turtle was born");
}
~CTurtle()
{
Print("Turtle is dead");
}
};
//+------------------------------------------------------------------+//| Script program start function |//+------------------------------------------------------------------+voidOnStart()
{
//--- массив указателей на объекты типа IAnimal
CiAnimal *animals[3];
//--- породим потомков CiAnimal и сохраним указатели на них в массив
animals[0] = new CCat;
animals[1] = new CDog;
animals[2] = new CTurtle;
//--- вызовем метод Sound() для каждого потомкаfor(int i = 0; i < ArraySize(animals); ++i)
animals[i].Sound();
//--- удалим объектыfor(int i = 0; i < ArraySize(animals); ++i)
delete animals[i];
}
//+------------------------------------------------------------------+
Т.е. если у животного нет своей реализации звука, то предполагается, что оно молчит ))
В том, что с помощью виртуальных методов реализуется полиморфизм - один из столпов ООП. Вот представьте себе стадо (группу) зверей, о котором писали выше. Там есть кошки, собаки, бараны и т.д. Пусть берём в цикле каждое животное и просим, чтобы оно издало звук. Заранее мы не знаем, кто нам попадётся. Но у каждого есть свой виртуальный метод озвучивания. И на этапе выполнения программы (run-time) он должен сработать и правильно озвучить выбранное животное.
Вот такими объяснениями, простите загажены, все учебники и примеры. Это ни о чём. Мне кажется это легко решается обычной перегрузкой функции… Это не утверждение, могу и заблуждаться…
Alexey Viktorov #: Если так, то зачем всё это городить если простая функция будет работать так-же… В чём прикол? В чём полезность виртуальности?
Перечитайте оба моих сообщения вдумчиво. Простая перегрузка методов не будет работать также. Класс CArray оперирует объектами CObject, он не знает про наследников. Если Compare не виртуальный, то будет вызван метод Compare класса CObject, а если виртуальный - класса-потомка.
что могут быть созданы потомки, которые реализуют коллекции объектов CObject. Это метод как раз и будет вызывать метод Compare у элементов коллекции. Этот объект передается в метод Compare посредством ссылки node. Вы реализуете свой класс CMyObject как потомок CObject
Вот такими объяснениями, простите загажены, все учебники и примеры. Это ни о чём. Мне кажется это легко решается обычной перегрузкой функции… Это не утверждение, могу и заблуждаться…
Алексей, у Вас есть критическое мышление, что продвигает Вас на шаг ближе ))
Вот возьмём мой пример выше и просто переопределим метод озвучивания.
class CiAnimal
{
public:
void Sound()
{
Print("silent");
}; // звук, который издает животное
};
//+------------------------------------------------------------------+//| Класс CCat наследуется от класса CiAnimal |//+------------------------------------------------------------------+class CCat : public CiAnimal
{
public:
CCat()
{
Print("Cat was born");
}
~CCat()
{
Print("Cat is dead");
}
void Sound()
{
Print("meou");
}
};
//+------------------------------------------------------------------+//| Класс CDog наследуется от класса CiAnimal |//+------------------------------------------------------------------+class CDog : public CiAnimal
{
public:
CDog()
{
Print("Dog was born");
}
~CDog()
{
Print("Dog is dead");
}
void Sound()
{
Print("guaf");
}
};
//+------------------------------------------------------------------+//| Класс CTurtle наследуется от класса CiAnimal |//+------------------------------------------------------------------+class CTurtle : public CiAnimal
{
public:
CTurtle()
{
Print("Turtle was born");
}
~CTurtle()
{
Print("Turtle is dead");
}
};
//+------------------------------------------------------------------+//| Script program start function |//+------------------------------------------------------------------+voidOnStart()
{
//--- массив указателей на объекты типа CiAnimal
CiAnimal *animals[3];
//--- породим потомков CiAnimal и сохраним указатели на них в массив
animals[0] = new CCat;
animals[1] = new CDog;
animals[2] = new CTurtle;
//--- вызовем метод Sound() CiAnimal для каждого потомкаfor(int i = 0; i < ArraySize(animals); ++i)
animals[i].Sound();
//--- удалим объектыfor(int i = 0; i < ArraySize(animals); ++i)
delete animals[i];
}
//+------------------------------------------------------------------+
В журнале мы увидим такое:
2024.12.1613:39:00.302 t3 (SBER,M5) Cat was born
2024.12.1613:39:00.302 t3 (SBER,M5) Dog was born
2024.12.1613:39:00.302 t3 (SBER,M5) Turtle was born
2024.12.1613:39:00.302 t3 (SBER,M5) silent
2024.12.1613:39:00.302 t3 (SBER,M5) silent
2024.12.1613:39:00.302 t3 (SBER,M5) silent2024.12.1613:39:00.302 t3 (SBER,M5) Cat is dead
2024.12.1613:39:00.302 t3 (SBER,M5) Dog is dead
2024.12.1613:39:00.302 t3 (SBER,M5) Turtle is dead
Т.е. программа всегда вызывала метод родительского класса, без учёта классовой иерархии.
Виртуальные методы полезны только при использовании указателей. Если указатели не используются, virtual не пригодится.
Полно примеров для начинающих, где есть, например, множество Животное с виртуальной функцией звука от него. И есть его производные "подмножества": собаки, кошки и т.д. И у каждого из них своя реализация общей виртуальной функции звука: лай, мяуканье и т.д.
И если используются указатели, то можно собаку обобщить, сказав всем, что это Животное (указатель). Но при этом оно будет лаять.
В итоге можно, например, наплодить (создать объекты) собак, кошек и баранов. Затем загнать их в один одинаковый загон Животных (массив указателей на Животных). И, вроде, в массиве все Животные, но звук будет каждый издавать свой: лаять, мяукать, блеять.
Хорошее объяснение!
В чём прикол? В чём полезность виртуальности?
В том, что с помощью виртуальных методов реализуется полиморфизм - один из столпов ООП. Вот представьте себе стадо (группу) зверей, о котором писали выше. Там есть кошки, собаки, бараны и т.д. Пусть берём в цикле каждое животное и просим, чтобы оно издало звук. Заранее мы не знаем, кто нам попадётся. Но у каждого есть свой виртуальный метод озвучивания. И на этапе выполнения программы (run-time) он должен сработать и правильно озвучить выбранное животное.
Полно примеров для начинающих, где есть, например, множество Животное с виртуальной функцией звука от него. И есть его производные "подмножества": собаки, кошки и т.д. И у каждого из них своя реализация общей виртуальной функции звука: лай, мяуканье и т.д.
И если используются указатели, то можно собаку обобщить, сказав всем, что это Животное (указатель). Но при этом оно будет лаять.
В итоге можно, например, наплодить (создать объекты) собак, кошек и баранов. Затем загнать их в один одинаковый загон Животных (массив указателей на Животных). И, вроде, в массиве все Животные, но звук будет каждый издавать свой: лаять, мяукать, блеять.
Прикол в том, что вы описываете интерфейс, либо абстрактный класс с чисто виртуальным методом. Вряд-ли какое-либо животное будет использовать реализацию из базового класса (для метода издавания звука).
Гораздо сложнее придумать простой пример для виртуальных методов, когда использование реализации базового класса может быть уместным на ряду с ее заменой производными классами. Лично я не могу простой пример придумать для этого.
То-есть функция в потомке просто заменяет функцию родителя?
Если так, то зачем всё это городить если простая функция будет работать так-же…
Да, можно перезагрузить функцию в потомке и она заменит родительскую.
Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий
Учёба. Классы. Нужна помощь.
fxsaber, 2024.11.22 19:54
Кусок кода (см. вложение) для их вычисления привожу здесь, как пример реальной задачи, которая просто решается только через ООП.
Например, если захотеть посмотреть процитированный исходник, то там будет использоваться слово virtual. Но для его работоспособности этот virtual не нужен, т.к.
Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий
Учёба. Классы. Нужна помощь.
fxsaber, 2024.12.16 10:30
Виртуальные методы полезны только при использовании указателей. Если указатели не используются, virtual не пригодится.
Т.е. все будет работать через механизм перегрузки, если убрать virtual.
Однако, по какой-то причине virtual там написан. Причина в том, что потенциально в будущем возможна работа с этими объектами через указатели. И тогда механизм перегрузки будет давать совсем не тот эффект, что потребуется. Прописывание виртуальности определяет разработчик часто на основе просто опыта/интуиции. Опытные почти сразу видят, что может быть virtual и прописывают. Даже если пока не собираются это использовать. Примерно так и получилось с CTrade.
Прикол в том, что вы описываете интерфейс, либо абстрактный класс с чисто виртуальным методом. Вряд-ли какое-либо животное будет использовать реализацию из базового класса (для метода издавания звука).
Гораздо сложнее придумать простой пример для виртуальных методов, когда использование реализации базового класса может быть уместным на ряду с ее заменой производными классами. Лично я не могу простой пример придумать для этого.
Может так случиться, что многие животные не издают звуков. Тогда базовая виртуальная функция звука животного - тишина. И нам нужно писать реализацию звука нового животного только тогда, когда мы знаем, как оно звучит. Не знаем - не прописываем. Т.е. удобно (код лаконичный), когда базовая виртуальная функция прописана.
Прикол в том, что вы описываете интерфейс, либо абстрактный класс с чисто виртуальным методом. Вряд-ли какое-либо животное будет использовать реализацию из базового класса (для метода издавания звука).
Можно сделать и реализацию в базовом классе как метод по умолчанию. Например:
Т.е. если у животного нет своей реализации звука, то предполагается, что оно молчит ))
В том, что с помощью виртуальных методов реализуется полиморфизм - один из столпов ООП. Вот представьте себе стадо (группу) зверей, о котором писали выше. Там есть кошки, собаки, бараны и т.д. Пусть берём в цикле каждое животное и просим, чтобы оно издало звук. Заранее мы не знаем, кто нам попадётся. Но у каждого есть свой виртуальный метод озвучивания. И на этапе выполнения программы (run-time) он должен сработать и правильно озвучить выбранное животное.
Вот такими объяснениями, простите загажены, все учебники и примеры. Это ни о чём. Мне кажется это легко решается обычной перегрузкой функции… Это не утверждение, могу и заблуждаться…
Если так, то зачем всё это городить если простая функция будет работать так-же… В чём прикол? В чём полезность виртуальности?
Да, логично. Но я бы наверное предпочел обязать себя явно реализовать молчание. Просто чтобы в дальнейшем ничего не провтыкать.
Я бы еще отладочную информацию добавил:
[edit]
Хотя, возможно не стояло прятать speak() в приватную секцию для рыбы.
Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий
Ошибки, баги, вопросы
Alain Verleyen, 2024.12.15 18:46
открытый интерфейс в иерархии классов следует уважать
[edit 2]
Та не, она же виртуальная, можно и спрятать, я думаю. Ведь область видимости виртуальных методов всегда указывается заново в производном классе.
Вот такими объяснениями, простите загажены, все учебники и примеры. Это ни о чём. Мне кажется это легко решается обычной перегрузкой функции… Это не утверждение, могу и заблуждаться…
Алексей, у Вас есть критическое мышление, что продвигает Вас на шаг ближе ))
Вот возьмём мой пример выше и просто переопределим метод озвучивания.
В журнале мы увидим такое:
Т.е. программа всегда вызывала метод родительского класса, без учёта классовой иерархии.