继承和析构函数-理论问题- c++

Inheritance and destructors - theoretical question - C++

本文关键字:理论问题 c++ 析构函数 继承      更新时间:2023-10-16
class A
{
    public:
         virtual void f(){ printf("A.f "); }
         ~A(){ f(); }
};
class B : public A
{
    A a;
    public:
         void f(){ printf("B.f "); }
         B(){ throw -1; }
        ~B(){ f(); }
};
int main()
{
    try{ B b; }
    catch(...){ printf("Exc");}
}

我是这么看的。在try块内部,在构造B b;时没有打印任何东西。街区结束了。我认为编译器首先销毁了A a;成员。因此,A.f()将被打印。这是否意味着销毁了class B实例?之后,编译器会简单地调用~A()(析构基类)吗?

我想我应该得到A.f(),然后是B.f()(析构类B实例),之后是A.f()(基类的析构函数)。编写这篇文章让我思考了一下。Exc将在课程结束时打印出来。我找了好几个题目都没找到。

编辑:输出Dev-C + + (GCC 3.4.2)

。f A.f Exc

这里确实有两个A对象。

  1. B继承自A,因此A的基类对象在B之前被首先实例化。
  2. 另一个A实例被创建,因为你有一个A类型的成员字段作为B的一部分。

当您创建B b时,您创建了基类A,以及实例A a

但是,您随后在B的构造函数中抛出异常,因此此时所有完全构造的对象都被析构,即

  • ~A()在实例A a上被调用。
  • ~A()在基类A上被调用。

这就解释了为什么你会得到A.f A.f Exc

B的析构函数将不会被调用,因为B的构造函数没有成功完成而没有完全构造。

您还没有向我们展示您得到的输出,只是一堆乱七八糟的文本,所以很难知道您在问什么。

然而,为了记录,你的代码的输出是:

。f A.f Exc


为什么?

  • b建设失败
  • bB析构函数没有被调用,但是它的成员的析构函数是1
  • 有一个A类型的成员,其析构函数调用f()函数。
  • 还有一个完全构建的A基础b;因此,bA析构函数也被调用,像以前一样调用A::f()
  • Exc当然是由周围的异常处理程序输出。

这是你想知道的吗?


<一口> 1> blockquote>

[n3290: 15.2/2]:任意存储时间的对象初始化或销毁由异常终止为其所有完全构造的子对象执行析构函数(不包括类联合的变体成员),即for主构造函数(12.6.2)已完成的子对象执行时,析构函数尚未开始执行。[. .]

顺序应为:A.f, A.f, Exc

当调用B的构造函数时,在进入之前,首先由于继承而调用A的构造函数。接下来,在进入B的构造函数之前(即在{之前),a是默认构造的。

B的构造只有在满足}时才算完成。但在那之前,你有一个throw语句。所以部分构造的B必须被销毁,它有一个对象a和继承的子对象a所以这两个都被销毁了,因此A.f和A.f

接下来,到达输出'Exc'的throw块

#include <stdio.h>
class A
{
    public:
         virtual void f(int i){ printf("A.f %in", i); }
         ~A(){ f(0); }
};
class B : public A
{
    A a;
    public:
         void f(int i){ printf("B.f %in", i); }
         B(){ throw -1; }
         ~B(){ f(1); }
};
int main()
{
    try{ B b; }
    catch(...){ printf("Excn");}
}

A的析构函数被调用两次,就是这样。

输出:

A.f 0
A.f 0
Exc

不能从构造函数或析构函数调用虚函数。它们不会作为虚函数工作,而是作为非虚函数调用。