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)的输出
A.f A.f Exc
答案 0 :(得分:10)
这里确实有两个A
个对象。
B
继承自A
,因此{B}之前首先实例化A
的基类对象。A
实例,因为A
的成员字段属于B
。创建B b
时,您可以创建基类A
,还可以创建实例A a
。
但是,然后在B
的构造函数中抛出异常,那么那个点上的所有完全构造的对象都被破坏了,即。
~A()
在实例A a
上调用。~A()
上调用A
。这可以解释为什么你得到A.f A.f Exc
。
B
的析构函数不会被调用,因为B
没有完全构造,因为它的构造函数没有成功完成。
答案 1 :(得分:4)
你没有向我们展示你得到的输出,只是一大堆文字,所以你很难知道你在问什么。
然而,为了记录,the output of your code is:
A.f A.f Exc
为什么?
b
失败。b
的{{1}}析构函数未被调用,但其成员的析构函数是 1 。B
类型的成员,其析构函数调用函数A
。f()
还有一个完整构建的A
基础;所以,b
的{{1}}析构函数也被调用,像以前一样调用b
。A
当然是由周围的异常处理程序输出的。这是你想知道的吗?
1 :
A::f()
任何存储持续时间的对象 初始化或销毁由异常终止 为所有完全构造的子对象执行的析构函数 (不包括类似联合类的变体成员),即for 主要构造函数(12.6.2)已完成的子对象 执行和析构函数尚未开始执行。 [..]
答案 2 :(得分:4)
订单应该是: A.f,A.f,Exc
当调用B的构造函数时,在进入之前,由于继承而调用第一个A的构造函数。接下来,在进入B的构造函数之前(即在{
之前),a
是默认构造的。
B的构造只有在达到匹配}
时才会完成。但在此之前你有一个抛出声明。所以部分构造的B必须被销毁,它有一个对象a
和继承的子对象A.所以这两个都被破坏了,因此A.f和A.f
接下来,您到达打印'Exc'的投掷区
答案 3 :(得分:0)
#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
答案 4 :(得分:0)