Не понимаю назначение virtual
На протяжении всего изучения языка никак не могу понять и усвоить назначение ключевого слова virtual
Заранее извиняюсь за сей бред что возможно мог сморозить,если лень читать то сразу посмотрите на предпоследнее предложение)
Из всяких форумов я вырыл и запомнил следующее, о этом волшебном слове:
- Когда что-то принимает различные формы,но тем не менее продолжает свою суть. Попробую объяснить просто. Думаю имеется ввиду что у меня есть какая-то там функция
DrawклассаBaseрисующая круг,тут я сделал её виртуальной,создал новый классBase2с такой же функциейDraw,наследовал базовый класс с кругом и после типо могу вызыватьBase b1=new Base();ну иBase2 b2=new Base();а дальше вызывать нужное рисование. Но уже тут,я не понимаю смысла. Окей,я видел рассуждения на каком-то форуме что-то типо:
Зачем это вам нужно? Нужно что бы постоянно не делать приведение к каждому классу(
пытался на память повторить код,но лучше не буду,а то будет просто смех какой-то)
Но ведь разве мне сложно делать приведение каждого? Да нет вроде,вызывать топорно тоже не сложно.
- Одновременно является носителем многих форм. Дальше был пример типо,у нас есть алмаз и есть графит,оба из углерода. Типо углерод принимает разные формы,он у нас тут виртуален. Окей,ну тут +- понятно,что в таком случае поставить виртуальность(поставить слово которое ставят все без объяснения)
Опять же,пункт описания для определения нужно ли ставить ключевое слово. Но зачем? не понятно.
Я не знаю что и написать.Из написанного мной же выше,я не могу прийти к выводу зачем мне использовать virtual и что это значит. Везде его вижу,аж стыдна,что я один такой не понимаю.
Помогите разобраться в этом слове, пожалуйста Х) я даже не столько синтаксис не понимаю,сколько смысл и преимущества в использовании
P.s. только пожалуйста,пишите простыми ответами,а то часто ответ вроде есть,но что бы его понять нужно загуглить и просидеть пол дня.
Ответы (1 шт):
Рассмотрим пример.
Некий разработчик создает библиотеку, с помощью которой, можно написать свою игру. Идея в том, чтобы можно было задать определения своих игровых объектов, их поведение, то как они выглядят в виде классов, слинковать с библиотекой, запустить код типа:
Game game = new Game();
game.addGameObject(new Hero());
game.addGameObject(new Enemy1());
game.addGameObject(new Enemy2());
game.run();
Game внутри себя хранит вектор игровых объектов, а run (среди прочего) вызывает код для рисования всех игровых объектов типа такого:
void Game::drawAllGameObjects() {
...
for (vector<GameObject*>::iterator it = gameObjects.begin(); it !=
gameObjects.end(); it++) {
(*it)->draw(canvas);
}
}
Тут классы Hero и Enemy1 - создаются разработчиком игры, про них разработчик библиотеки ничего не знает. Он написал метод run и класс GameObject предполагая, что разработчик игры для каждого игрового объекта создаст класс-наследник от GameObject и напишет реализацию draw. Она будет рисовать используя примитивы типа drawPixel, drawLine и copyBitmap игровой объект.
Из библиотеки:
struct GameObject {
virtual void draw(Canvas* canvas) {
}
};
Из программы:
struct Hero : GameObject {
void draw(Canvas* canvas) override { // тут ключевое слово virtual необязательно
...
}
};
При этом реализацию библиотеки, в частности метод drawAllObjects разработчик библиотеки скомпилирует заранее и будет распостранять в виде бинарного файла (т.е. без исходного кода).
Для того, чтобы в функции drawAllObjects был вызван нужный метод (т.е. для Hero метод Hero::draw, а для Enemy1 - Enemy1::draw), о которых разработчик библиотеки ничего не знает, и нужно объявить метод GameObject::draw как virtual. В этом случае компилятор создаст правильный код для вызова метода из конкретного объекта, который будет доступен только во время выполнения (грубо - это будет косвенный вызов метода, т.е. адрес метода не прошит в коде, а берется из таблицы, которая хранится в конкретном объекте).
Если нет virtual, то в месте вызова draw компилятором будет вставлен вызов метода GameObject::draw не зависимо от типа объекта в it и эта задумка с drawAllGameObject не будет работать.