Подтвердить что ты не робот

Что означает "имеет виртуальный метод... но не виртуальный деструктор" означает во время компиляции С++?

#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); }
  };

Предупреждение о компиляции

Class '[[email protected]' has virtual method 'area' but non-virtual destructor

Как понять это предупреждение и как улучшить код?

[EDIT] эта версия сейчас правильная? (Попытка дать ответ, чтобы разъяснить мне концепцию)

#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(){}
  };
4b9b3361

Ответ 1

Если класс имеет виртуальный метод, это означает, что вы хотите, чтобы другие классы наследовали его. Эти классы могут быть уничтожены с помощью ссылки на базовый класс или указателя, но это будет работать только в том случае, если базовый класс имеет виртуальный деструктор. Если у вас есть класс, который должен использоваться полиморфно, его также следует удалить полиморфно.

Этот вопрос также подробно рассмотрен здесь. Ниже приведена полная примерная программа, демонстрирующая эффект:

#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
}

Вывод:

Destructor of FooBase
Destructor of Bar
Destructor of BarBase

Обратите внимание, что delete bar; вызывает оба деструктора, ~Bar и ~BarBase, а delete foo; вызывает только ~FooBase. Последнее - это undefined поведение, поэтому эффект не гарантируется.

Ответ 2

это означает, что вам нужен виртуальный деструктор в базовом классе с виртуальными методами.

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

Отключение может привести к поведению undefined, обычно появляется как утечка памяти в таких инструментах, как valgrind.

Ответ 3

Это просто означает, что такой код, как

CPolygon* p = new CRectangle;
delete p;

... или любой другой способ, будет по существу не вести себя правильно, поскольку CPolygon не является полиморфным при удалении, а часть CRectange не будет уничтожена должным образом.

Если вы не собираетесь удалять полиграфы CRectangle и CPolygon, это предупреждение не имеет смысла.