0

我有两个类,而B派生A.

我创建了一个指向 的指针A,称为:a2。请看看我的main功能。

这条线有什么作用?

a2 = new B();

为什么当我 delete 时a2,只有 A 的析构函数被激活?

#include <iostream>
using namespace std;

class A {
    int num;
  public:
    A() { cout << "constructor of A\n"; }
    void set_num(int new_num) { cout << "set_num of A" << endl; num = new_num; }
    void print() { cout << "print of A: ";  cout << num << endl; }
    ~A() { cout << "destructor of A\n"; }
};

class B: public A {
    int num;
  public:
    B() { cout << "constructor of B\n"; }
    void set_num(int new_num) { cout << "set_num of B" << endl; num = new_num; }
    void print() { cout << "print of B: ";  cout << num << endl; }
    ~B() { cout << "destructor of B\n"; }
};

void main() {
    A *a2;
    a2 = new B();
    delete a2;
}

这是输出:

constructor of A
constructor of B
destructor of A

每个帮助表示赞赏!

4

3 回答 3

1

首先让你的析构函数虚拟化......

虚拟 ~A()... 虚拟 ~B()...

看这里:什么时候使用虚拟析构函数?

于 2013-05-03T22:00:05.447 回答
1

如果通过指向基子对象的指针删除对象,则基类的析构函数必须是virtual

class A
{
public:
    virtual ~A() { /* ... */ }
    // ...
};

(这将自动使所有派生类析构函数成为虚拟的,因此您不必在那里拼写出来。)

原因是 C++11 标准的第 5.3.5/3 条:

如果待删除对象的静态类型与其动态类型不同,则静态类型应为待删除对象动态类型的基类,且静态类型应具有虚析构函数或行为未定义。

我相信你可以想象为什么虚拟析构函数是,但对于一个简单的例子,想象指向基址的指针(如你的a2)甚至不必在数字上与指向实际对象的指针相同——但是您需要确切的指针来释放内存。所以很明显,在找出正确地址的过程中需要一些魔法。虚拟析构函数结合了这种魔力。

于 2013-05-03T22:05:21.517 回答
1

所以这里最简单和最方便的解决方案是使用虚拟析构函数,但让我也展示另一种解决方案:帮助编译器。类型推断在这里很有用 - 如果您将对象声明为尽可能具体的类型,您将获得预期的行为:

int main()
{
    B *a2;
    a2 = new B();
    delete a2;
}

输出

constructor of A
constructor of B
destructor of B
destructor of A

另外,main()应该返回int,而不是void

于 2013-05-03T22:07:14.380 回答