开发者

Inheritance and destructors - theoretical question - C++

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.

  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.


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. [..]


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜