Ne pas mettre un "destructeur virtuel à l'intérieur d'une interface", par définition, pas une interface plus?

donc voici la boite dans laquelle je suis. Je veux comprendre pourquoi il est important d'avoir un "destructeur virtuel dans votre classe d'interface". Vous verrez pourquoi ces trucs sont entre guillemets si vous pouvez les accrocher jusqu'à la fin... Je veux aussi que tout le vocabulaire soit absolument correct. Voici où j'en suis avec le processus jusqu'à présent:

  1. parfois vous avez des classes de base, parfois vous avez des classes dérivées qui héritent des classes de base.

  2. si vous avez un pointeur de base qui se trouve pointant vers un objet dérivé, et de plus vous voulez qu'un appel de fonction membre fait à partir de cet objet de base-pointeur-pointeur-vers-un-dérivé se comporte comme si il avait été appelé à partir de l'Objet dérivé, alors la fonction membre que vous appelez devrait être déclarée virtuelle dans la classe de base.

  3. une interface est n'importe quelle classe avec seulement pure virtuelle fonction. Si vous dérivez une nouvelle classe de cette classe d'interface et implémentez toutes les fonctions virtuelles pures, alors vous pouvez enfin créer une instance de la classe dérivée.

  4. Vous ne pouvez jamais avoir une instance d'une classe d'interface, MAIS vous pouvez avoir un exemple d'un pointeur vers l'interface de la classe.

  5. dans le cas où vous avez un pointeur-à-interface-classe qui pointe effectivement à un objet de la dérivée classe (en fait, je suppose qu'il le faudrait toujours si #4 est correct), et si vous décidez de supprimer cet objet par votre pointeur, alors si vous n'avez pas de "destructeur virtuel à l'intérieur de votre classe d'interface", votre intention de détruire l'Objet dérivé ne sera exécutée qu'en tant qu'appel à détruire l'objet de base (i.e. la classe d'interface) et puisqu'il n'y a pas de destructeur virtuel, les choses n'arriveront jamais au point où le destructeur pour l'Objet dérivé est réellement appelé -- provoquant ainsi la mémoire fuite.

Phew. OK, si ça semble juste, sur ma question. Suffit-il de déclarer un destructeur virtuel à l'intérieur de votre interface comme ceci:

virtual ~iFace();

ça me semble mal... alors que se passe-t-il si vous faites le destructeur virtuel pur comme ceci:

virtual ~iFace() = 0;

comme ce ne sont que des déclarations, est-ce que l'une d'elles compte pour être un "destructeur virtuel à l'intérieur de votre classe d'interface"? Pouvez-vous même avoir un destructeur déclaré Mais non défini? Seulement si elle est virtuelle pure, je suppose...

donc, revenons à la question du titre... Je vais vraiment aussi vite que je peux... Ici, c'est le money shot... Si votre "destructeur virtuel dans votre classe d'interface" nécessite au moins une définition vide comme celle-ci:

virtual ~iFace() {};

alors cette fonction de membre n'est pas purement virtuelle (ne peut pas l'être parce que vous lui avez donné une définition) et donc votre classe n'est plus une interface (elle ne contient pas seulement des fonctions de membre virtuel pures).

cela implique que si vous définissez un destructeur virtuel pour votre interface, alors vous n'avez plus d'interface (mais juste une classe de base abstraite). Est-ce juste un abus de langage? Dois-je comprendre ce qui se passe?

note: tout cela est venu de me demander "Qu'est-ce qu'une interface?"et en lisant cette question réponses: Comment déclarer une interface en C++?

Espérons que ce n'était pas trop longue d'un pied trop court un tour, mais je suis déterminé à la compréhension complète de ces concepts et de leur vocabulaire associé.

24
demandé sur Community 2011-08-06 17:09:00

4 réponses

pourquoi Abstract class destructeur devrait être virtuel et avoir une définition?

Appel delete sur un polymorphe de la classe de Base pointeur pointant vers un objet de classe Dérivée et la classe de Base n'ayant pas un destructeur virtuel provoque une un Comportement Indéfini .

donc vous devez déclarer le destructeur de la classe de base polymorphique comme virtual . Lorsque vous déclarez votre explicitement le destructeur virtuel, vous devez fournir une définition. C'est parce que le compilateur par défaut génère(définit) un destructeur pour chaque classe, mais si vous déclarez explicitement le destructeur alors le compilateur ne le fait pas et le laisse pour vous fournir une définition pour votre propre destuctor. Cela a du sens parce que le compilateur voit une déclaration explicite comme une indication que vous voulez faire certaines opérations non triviales(même si vous n'avez pas besoin de le faire)) dans le destructeur et il vous offre la possibilité de le faire en vous forçant à donner la définition.


mythe 1:

il y a quelque chose appelé Interface en C++.

NON

C++ en tant que langue ne fournit pas de Interface Ce que vous appelez les Interface est appelé Abstract class en C++. Abstract Classes sont utilisés pour simuler le comportement de Interface en C++.

Qu'est-ce qu'une classe abstraite?

Par définition, une classe abstraite doit avoir au moins une fonction virtuelle pure.


Mythe 2:

toutes les fonctions à l'intérieur de la classe abstraite doivent être purement virtuelles.

NO

Abstract classes il n'est pas nécessaire que toutes les fonctions qu'ils contiennent soient purement virtuelles. Un objet D'un Abstrait ne peut pas être créé s'il a au moins une fonction purement virtuelle. Si, comme vous l'avez mentionné, vous pouvez créer des pointeurs.


mythe 3:

les fonctions virtuelles pures ne peuvent pas avoir de définition.

NON

Il est parfaitement valide pour les fonctions virtuelles pures d'avoir une définition.


pourquoi aurais-je besoin d'un Pure virtual function avec définition?

Le Code parle plus fort que les mots, alors voici un exemple simple:

attention: code non compilé uniquement pour la démonstration

class IMyInterface
{
    int i;
    int j;
    public:
        virtual void SetMembers(int ii, int jj)=0;
};

/*The pure virtual function cannot be inline in the class definition*/
/*So this has to be here*/
void IMyInterface::SetMembers(int ii, int jj)
{
    i = ii;
    j = jj;
}

class Myclass: public IMyInterface
{
    int k;
    int l;
    public:
        virtual void SetMembers(int ll, int m, int a, int b)
        {
             k = ll;
             l = m;
             IMyInterface::SetMembers(a,b);
         }
};

int main()
{

    MyClass obj;
    obj.SetMembers(10,20,30,40);
    return 0;
}
26
répondu Alok Save 2011-08-06 14:32:46

C++ n'a pas d'entité d'interface native. Les Interfaces sont implémentées sous forme de classes régulières.

ce qui fait d'une classe une interface en C++ n'est donc pas quelque chose qui a un accord universel. Personnellement, je considère qu'une classe est une interface si elle n'a pas de membres de données, aucun constructeur déclaré par l'utilisateur et toutes ses fonctions sont purement virtuelles-à l'exception possible de son destructeur - et toutes ses classes de base, le cas échéant, sont aussi des interfaces. Si une classe ne correspond pas tout à fait à toutes ces propriétés je pourrais l'appeler comme une interface "fat" (généralement pas un compliment!).

si vous voulez supprimer des classes polymorphiques attribuées dynamiquement à travers un pointeur vers une classe de base (telle qu'une classe" interface"), alors la classe de base destructeur doit doit être déclaré virtual . Cela signifie qu'il doit s'agir d'un destructeur déclaré par l'utilisateur et non d'un destructeur implicitement déclaré qui ne serait pas virtual .

une fois que vous déclarez explicitement un destructeur, vous devez lui fournir une implémentation. (Un destructeur de classe de base sera toujours utilisé lorsque vous détruisez une instance d'une classe dérivée de celle-ci, que le destructeur de classe de base soit ou non déclaré pur virtuel, virtuel ou non virtuel.) Ceci est purement un détail D'implémentation du langage C++. Cela ne signifie pas que votre classe de base est moins une "interface", si vous avez une classe d'interface alors il est très probable que la l'implémentation du destructeur sera vide dans tous les cas - vous n'avez pas de membres ou de classes de base avec des membres à surveiller.

si votre interface a au moins quelques fonctions virtuelles pures alors il n'y a pas de véritable mérite à marquer le destructeur comme pur, votre classe d'interface est déjà une classe abstraite. Les Destructeurs de classe dérivés ne supplantent pas techniquement Les Destructeurs de classe de base donc vous n'avez pas besoin des classes dérivées pour fournir des destructeurs déclarés par l'utilisateur ou quelque chose comme que.

déclarer un destructeur comme un pur virtuel vous prive également de la capacité de fournir la définition du destructeur en ligne dans la définition de la classe, bien qu'il s'agisse d'un détail mineur.

9
répondu CB Bailey 2011-08-06 22:11:08

"Une interface est une classe avec seulement des fonctions virtuelles pures"

-- le concept en c++ est appelé classe abstraite . Une classe abstraite est une classe avec au moins une fonction virtuelle pure. Il n'exige pas que toutes ses fonctions de membre soient purement virtuelles. Vous ne pouvez pas instancier une classe abstraite.

" cela signifierait que si vous définir un destructeur virtuel pour votre interface, alors vous n'avez plus d'interface (mais juste quelques classe de base abstraite). Est-ce juste un abus de langage? Dois-Je comprendre ce qui se passe?"

-- au contraire, vous devez fournir une définition pour le destructeur même s'il est purement virtuel parce que les destructeurs sont toujours appelés de manière descendante dans la hiérarchie de l'héritage.

Standard 12.4:

un destructeur peut être déclaré virtuel (10.3) ou purement virtuel (10.4); si des objets de cette classe ou de toute classe dérivée sont créés dans le programme, le destructeur doit être défini.

exemple de type

class A
{
public:
   // this is stil a pure virtual function
   // when there is a definition
   virtual ~A() = 0;
};

class B: public A
{};

int main()
{
   // fail to link due to missing definition of A::~A()
   B b;
}
7
répondu Eric Z 2011-08-06 14:48:10
  1. OK.
  2. OK; si la fonction de membre n'est pas déclarée virtuelle dans la classe de base, celle de la classe de base est appelée; si la fonction de membre n'est ni définie ni déclarée pure virtuelle dans la classe de base, vous obtenez une erreur.
  3. en C++ vous n'avez pas d'interfaces comme vous en avez en Java et en C#; Les classes abstraites de base en C++ combinent les interfaces et les classes abstraites telles qu'elles sont présentes dans les deux dernières langues. Une Classe C++ est abstraite si elle a au moins une fonction membre virtuelle pure.
  4. Remplacer interface avec la classe abstraite .
  5. formellement, vous ne pouvez pas faire de suppositions sur ce qui se passe si vous supprimez une classe dérivée d'un pointeur vers une classe de base si le destructeur de la classe de base n'est pas déclaré virtuel.

compte tenu de tout cela, en général votre classe de base abstraite aura déjà un peu de pure fonction de membre virtuel qui assure qu'il ne sera pas possible de l'instancier, donc la façon habituelle de faire les choses est de définir un destructeur virtuel en ligne qui ne fait rien.

2
répondu Nicola Musatti 2011-08-06 13:31:18