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;
. T开发者_运维知识库he 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
You really have two A
objects here.
B
inherits fromA
, so a base class object ofA
is instantiated first before B is.- Another
A
instance is created as you have a member field of typeA
as part ofB
.
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 instanceA a
.~A()
is called on the base classA
.
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.
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
'sB
destructor is not invoked, but destructors for its members are1.- It has a member of type
A
, whose destructor calls the functionf()
. - There is also a fully-constructed
A
base ofb
; so,b
'sA
destructor is also invoked, callingA::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. [..]
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
#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
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.
精彩评论