web-dev-qa-db-fra.com

Que signifie l'avertissement «a une méthode virtuelle ... mais un destructeur non virtuel» pendant la compilation C ++?

#include <iostream>
using namespace std;

class CPolygon {
  protected:
    int width, height;
  public:
    virtual int area ()
      { return (0); }
  };

class CRectangle: public CPolygon {
  public:
    int area () { return (width * height); }
  };

A un avertissement de compilation

Class '[C@1a9e0f7' has virtual method 'area' but non-virtual destructor

Comment comprendre cet avertissement et comment améliorer le code?

[MODIFIER] cette version est-elle correcte maintenant? (Essayer de donner une réponse pour m'élucider avec le concept)

#include <iostream>
using namespace std;

class CPolygon {
  protected:
    int width, height;
  public:
    virtual ~CPolygon(){};
    virtual int area ()
      { return (0); }
  };

class CRectangle: public CPolygon {
  public:
    int area () { return (width * height); }
    ~CRectangle(){}
  };
38
qazwsx

Si une classe a une méthode virtuelle, cela signifie que vous souhaitez que d'autres classes en héritent. Ces classes pourraient être détruites via une référence ou un pointeur de classe de base, mais cela ne fonctionnerait que si la classe de base a un destructeur virtuel. Si vous avez une classe qui est censée être utilisable de manière polymorphe, elle doit également être supprimable de manière polymorphe.

Cette question est également répondue en profondeur ici . Voici un exemple de programme complet qui illustre l'effet:

#include <iostream>

class FooBase {
public:
    ~FooBase() { std::cout << "Destructor of FooBase" << std::endl; }
};

class Foo : public FooBase {
public:
    ~Foo() { std::cout << "Destructor of Foo" << std::endl; }
};

class BarBase {
public:
    virtual ~BarBase() { std::cout << "Destructor of BarBase" << std::endl; }
};

class Bar : public BarBase {
public:
    ~Bar() { std::cout << "Destructor of Bar" << std::endl; }
};

int main() {
    FooBase * foo = new Foo;
    delete foo; // deletes only FooBase-part of Foo-object;

    BarBase * bar = new Bar;
    delete bar; // deletes complete object
}

Production:

Destructor of FooBase
Destructor of Bar
Destructor of BarBase

Notez que delete bar; provoque les deux destructeurs, ~Bar et ~BarBase, à appeler, tandis que delete foo; appelle uniquement ~FooBase. Ce dernier est même comportement indéfini , donc cet effet n'est pas garanti.

77
Björn Pollex

cela signifie que vous avez besoin d'un destructeur virtuel sur une classe de base avec des méthodes virtuelles.

struct Foo {
  virtual ~Foo() {}
  virtual void bar() = 0;
};

Le laisser de côté est peut conduire à un comportement indéfini, apparaît généralement comme une fuite de mémoire dans des outils comme valgrind.

14
Tom Kerr

Cela signifie simplement qu'un code comme

CPolygon* p = new CRectangle;
delete p;

... ou quoi que ce soit enveloppant dans n'importe quel pointeur intelligent, ne se comportera essentiellement pas correctement car CPolygon n'est pas polymorphe à la suppression, et la partie CRectange ne sera pas détruite correctement.

Si vous n'allez pas supprimer polymorphiquement CRectangle et CPolygon, cet avertissement n'a pas de sens.

2
Emilio Garavaglia