Par exemple t'as une classe Forme, tu veux pouvoir calculer l'aire d'une forme donc tu crées une méthode aire().
T'as 2 classes filles Carré, et Triangle qui héritent de Forme. L'aire d'un carré ne se calcule pas comme celle d'un triangle, donc tu redéfinis la méthode aire() dans ces 2 classes.
Tu peux créer un pointeur sur Triangle ou un Carré de cette façon :
Triangle* triangle = new Triangle();
Carré* carré = new Carré();
Quand tu appelles la méthode aire() de ces objets, tu appelles la méthode aire() de la classe Triangle ou Carré puisque tu l'as redéfinie.
Tu peux aussi créer un pointeur sur une Forme, et mettre un Triangle (ou un Carré) dedans, car Triangle dérive de Forme.
Forme* forme = new Triangle();
Si tu appelles la méthode aire() de cet objet, qu'est-ce qui se passe ?
Si la méthode aire() de Forme n'est pas virtual, alors c'est la méthode aire() de la classe Forme qui est appelée, car forme est un pointeur sur une Forme.
Si la méthode aire() de Forme est virtual, alors c'est la méthode aire() de la classe Triangle qui est appelée, car bien que forme soit un pointeur sur une Forme, sa vraie classe est Triangle.
Voilà la différence entre une méthode virtual ou pas.
Ensuite pourquoi tu voudrais stocker des Triangle ou des Carré dans des Forme* ? Bah si tu veux mettre tous tes Triangle et Carré dans un même tableau (ou vector) par exemple, et calculer l'aire de toutes les formes de ton tableau en utilisant une méthode qui a le même nom (aire).
Sinon petite info qui peut servir pour ton contrôle (genre question de cours) demain, si tu spécifies dans une classe mère qu'une méthode est virtuelle, alors elle le sera aussi dans ses classes filles même si tu n'écris pas explicitement virtual en redéfinissant la méthode dans les classes filles.