Что означает "имеет виртуальный метод... но не виртуальный деструктор" означает во время компиляции С++?
#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(){}
};
Ответы
Ответ 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, это предупреждение не имеет смысла.