Interfaces
Une interface est une classe qui n’a que des fonctions virtuelles pures publiques, rien de privé et aucun champ/propriété.
Les interfaces ne peuvent pas être construites en tant que telles.
Une interface sert à définir une sorte de contrat auquel les classes qui en héritent doivent se plier. Les classes filles doivent implémenter toutes les fonctions marquées en virtuelles pures dans l’interface.
Destruction
Problématique
Lorsque l’on veut détruire un objet construit à partir d’une classe fille uniquement accessible par un pointeur ou une référence sur l’interface, on reçoit l’avertissement qui suit.
// main.cpp
#include <iostream>
class ITata {
public:
virtual void tata() = 0;
};
class Tata : public ITata {
public:
~Tata() {
std::cout << "destructor called\n";
}
void tata() {}
};
int main()
{
ITata *instance{new Tata};
delete instance;
}
$ g++ main.cpp -Wall -Wextra
main.cpp: In function ‘int main()’:
main.cpp:12:5: warning: deleting object of abstract class type ‘ITata’ which has non-virtual destructor will cause undefined behavior [-Wdelete-non-virtual-dtor]
12 | delete instance;
| ^~~~~~~~~~~~~~~
$ ./a.out
$
Cela signifie que le compilateur ne sait pas comment détruire notre objet. Il n’arrive pas à trouver le destructeur de Tata notre classe fille.
À l’exécution on remarque aussi qu’aucun message ne s’affiche, alors que le destructeur de Tata est supposé afficher quelque chose.
Solution
#include <iostream>
class ITata {
public:
virtual ~ITata() = default;
virtual void tata() = 0;
};
class Tata : public ITata {
public:
~Tata() {
std::cout << "destructor called\n";
}
void tata() override {}
};
int main()
{
ITata *instance{new Tata};
delete instance;
}
Cela permet de mettre le destructeur dans la vtable de notre objet de sorte à ce que delete le trouve au moment de le détruire.
On peut vérifier que le bon destructeur est appelé en compilant et en lançant à nouveau :
$ g++ main.cpp -Wall -Wextra
$ ./a.out
destructor called