关于多态性:在C ++编译期间,“具有虚拟方法……但非虚拟析构函数”警告是什么意思?

What does 'has virtual method … but non-virtual destructor' warning mean during C++ compilation?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#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); }
  };

有编译警告

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

如何理解此警告以及如何改进代码?

[编辑]这个版本现在正确吗?(试图给出答案以阐明自己的概念)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#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
}

输出:

1
2
3
Destructor of FooBase
Destructor of Bar
Destructor of BarBase

注意,delete bar;导致调用~Bar~BarBase这两个析构函数,而delete foo;只调用~FooBase。后者甚至是未定义的行为,因此无法保证效果。


这意味着您需要一个带有虚方法的基类上的虚析构函数。

1
2
3
4
struct Foo {
  virtual ~Foo() {}
  virtual void bar() = 0;
};

不使用is->strike>会导致未定义的行为,通常在valgrind等工具中显示为内存泄漏。


它仅仅意味着

1
2
CPolygon* p = new CRectangle;
delete p;

…或者任何包裹在智能指针上的东西,基本上不会表现正确,因为CPolygon在删除时不是多态的,并且缝隙部分不会被正确破坏。

如果你不想删除crectangle和cpolygon多态性,那么这个警告是没有意义的。