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

发布于 2024-12-03 09:08:44 字数 745 浏览 0 评论 0原文

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; 成员。因此将打印 Af() 。这是否意味着B类实例的销毁已经完成?之后,编译器会简单地调用 ~A() (破坏基类)吗?

我想我应该先得到 Af(),然后是 Bf() (破坏类 B 实例),然后再次得到 Af() (基类的析构函数)。编译这个让我思考了一些。 当然,Exc 会在最后打印。 我已经浏览了几个主题,但没有找到任何东西。

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

AF AF 执行

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

So here's how I see it. Inside the try block, nothing is being printed while constructing B b;. The block ends. I think compiler is destructing the A a; member first. So A.f() would be printed. Does that mean the destruction of class B instance is finished? After that, would compiler simply call ~A() (destructing base class)?

I thought I should've got A.f(), then B.f() (destructing class B instance) and after that A.f() again (destructor of base class). Compiling this made me think a little.
Exc is being printed at the end of course.
I've gone through several topic and haven't found anything.

EDIT: Output from Dev-C++ (GCC 3.4.2) is

A.f A.f Exc

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

╭ゆ眷念 2024-12-10 09:08:44

这里确实有两个 A 对象。

  1. B 继承自 A,因此 A 的基类对象先于 B 实例化。
  2. 当您有一个 A 类型的成员字段作为 B 的一部分时,就会创建另一个 A 实例。

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

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

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

这可以解释为什么你会得到Af Af Exc

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

You really have two A objects here.

  1. B inherits from A, so a base class object of A is instantiated first before B is.
  2. Another A instance is created as you have a member field of type A as part of B.

When you create B b, you create the base class A, and also the instance A a.

However, you then throw the exception in B's constructor, so then all fully-constructed objects at that point are destructed, that is.

  • ~A() is called on the instance A a.
  • ~A() is called on the base class A.

That would explain why you get A.f A.f Exc.

B's destructor would not be called because B wasn't fully constructed as its constructor did not finish successfully.

骑趴 2024-12-10 09:08:44

您没有向我们展示您得到的输出,只是一堵胡言乱语的文字,所以很难知道您在问什么。

但是,根据记录,代码的输出是

AF AF 执行


为什么?

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

这是你想知道的吗?


1

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

You haven't shown us the output you get, just a wall of ranty text, so it's hard to know what you're asking.

However, for the record, the output of your code is:

A.f A.f Exc


Why?

  • Constructing b fails.
  • b's B destructor is not invoked, but destructors for its members are1.
  • It has a member of type A, whose destructor calls the function f().
  • There is also a fully-constructed A base of b; so, b's A destructor is also invoked, calling A::f() as before.
  • Exc is of course output by the surrounding exception handler.

Is this what you wanted to know?


1:

[n3290: 15.2/2]: An object of any storage duration whose
initialization or destruction is terminated by an exception will have
destructors executed for all of its fully constructed subobjects
(excluding the variant members of a union-like class), that is, for
subobjects for which the principal constructor (12.6.2) has completed
execution and the destructor has not yet begun execution. [..]

初吻给了烟 2024-12-10 09:08:44

顺序应该是:
Af, Af, Exc

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

仅当 B 达到匹配的 } 时,B 的构造才算完成。但在此之前你有一个 throw 语句。因此,部分构造的 B 必须被销毁,它有一个对象 a 和继承的子对象 A。因此,这两个对象都被销毁,因此 Af 和 A​​f

接下来,您将到达 throw 块,其中 'Exc'被打印

The order should be:
A.f, A.f, Exc

When B's constructor is invoked, before entering, first A's constructor is invoked due to inheritance. Next, before entering B's constructor (i.e. before {), a is default constructed.

B's construction would be complete only if it reaches matching }. But before that you have a throw statement. So the partially constructed B has to be destroyed, which has one object a and the the inherited subobject A. So both these are destroyed, hence A.f and A.f

Next, you reach the throw block where 'Exc' is printed

雨夜星沙 2024-12-10 09:08:44
#include <stdio.h>

class A
{
    public:
         virtual void f(int i){ printf("A.f %i\n", i); }
         ~A(){ f(0); }
};

class B : public A
{
    A a;

    public:
         void f(int i){ printf("B.f %i\n", i); }
         B(){ throw -1; }
         ~B(){ f(1); }
};

int main()
{
    try{ B b; }
    catch(...){ printf("Exc\n");}
}

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

输出:

A.f 0
A.f 0
Exc
#include <stdio.h>

class A
{
    public:
         virtual void f(int i){ printf("A.f %i\n", i); }
         ~A(){ f(0); }
};

class B : public A
{
    A a;

    public:
         void f(int i){ printf("B.f %i\n", i); }
         B(){ throw -1; }
         ~B(){ f(1); }
};

int main()
{
    try{ B b; }
    catch(...){ printf("Exc\n");}
}

Destructor of A is called twice, that's it.

Output:

A.f 0
A.f 0
Exc
橪书 2024-12-10 09:08:44

您不能从构造函数或析构函数调用虚函数。它们不会作为虚拟函数工作,而是被称为非虚拟函数。
您可以在常见问题解答此处阅读相关内容 以及有关构造函数的相关主题 此处

You can't call virtual functions from constructor or destructor. They won't work as virtual but will be called as non-virtual functions.
You can read about it in FAQ here and in related theme about constructors here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文