2

I was going through some online quiz on C++ and below is the question I bumped into

http://www.interqiew.com/ask?ta=tqcpp01&qn=3

class A
{
public:
    A(int n = 2) : m_i(n) { }

    ~A() { std::cout << m_i; }

protected:
    int m_i;
};

class B
    : public A
{
public:
    B(int n) : m_a1(m_i + 1), m_a2(n) { }

public:
    ~B()
    {
        std::cout << m_i;
        --m_i;
    }

private:
    A m_a1;
    A m_a2;
};

int main()
{
    { B b(5); }

    std::cout << std::endl;

    return 0;
}

Answer comes out to be "2531" -

I was expecting the answer to be "21" - with rationale as below (which seems to be faulty):

Object B is created with three member variables with starting value 2 - 253

So when the destructor would be called would be deleted in reverse order.

For this case here destructor will call inherited part - we print 2 we decrement the value and go to 1 and then base while removing would be printed - so answer 21

How are variables m_a2 and m_a1 getting printed - not able to understand. Also its getting printed ( value 53) in the base part ( i.e. Class A)

SCFrench
  • 8,244
  • 2
  • 31
  • 61
oneday
  • 629
  • 1
  • 9
  • 32
  • Useless code obfuscation in B taking a member of A to initialize it's own member. –  May 22 '15 at 19:27
  • `m_a2` and `m_a1` are destroyed when their containing object, `b`, is destroyed. Since the destructor of `A` outputs things, things are output when they are destroyed. – molbdnilo May 22 '15 at 19:40

3 Answers3

4

Lets consider the constructor

B(int n) : m_a1(m_i + 1), m_a2(n) { }

It is equivalent to

B(int n) : A(), m_a1(m_i + 1), m_a2(n) { }

So at first m_i is initialized by the default argument of the constructor A and will be equal to 2. Then m_a1 will be initialized by m_i + 1, that is, it will be equal to 3. And at last m_a2 will be equal to 5 for the call of B( 5 )

Then when the destructor of B will be called it outputs

std::cout << m_i;

that is

2

and then decreases m_i

--m_i;

Destructors of the data members are called in the reverse order relative to their constructions. So at first there will be called the destructor for m_a2 and it will output

5

then there will be called the destructor for m_a1 and it will output

3

and at last there will be called the destructor of the base class that will output

1

So you will get

2531

As for your question then the destructor of A is called three times: two times when data members m_a1 and m_a2 of class B are being destroyed (because they have type class A) and when the base class constructor is called.

SCFrench
  • 8,244
  • 2
  • 31
  • 61
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Thanks Vlad - I am able to follow the part till destructor for m_a2 will be called - Confusion part is " and it will output " - I am able to understand part that 5 and 3 would be destructed - I understanding is this would happen when we leave inherited class B - but what output shows is those values are printed in base class - how the values of m_a2 and m_a1 are available at base class and how they are printed - if you can give one more shot at explaining that part - I would be greatful - – oneday May 22 '15 at 19:45
  • I think with your edited answer - that with each destruction of data member base class is called because they are of type class A- was the part I missed - thank you so much for the explanation - I get it now !! – oneday May 22 '15 at 19:48
1

2531 is a correct answer. The order of calling destructors is always opposed to the order of calling constructors.

  • 2 - destructor of B
  • 5,3 - destructors of class fields in order opposed to the order of initializing
  • 1 - destructor of super class

see: Order of member constructor and destructor calls

Community
  • 1
  • 1
Piotr Siupa
  • 3,929
  • 2
  • 29
  • 65
  • 5,3 - destructors of class fields in order opposed to the order of initializing -- Conceptually I do understand it would be done in opposite order. what I am still confused about is how below line of code ~A() { std::cout << m_i; } prints 53 -- My thinking is ~B() { std::cout << m_i; --m_i; } -- when executed would print 2 which it is ... and remove 53 - so we are only left with 1 when we reach superclass - which seems to be incorrect understanding - which I am not able to understand – oneday May 22 '15 at 19:33
  • @oneday The two `A` member variables of `B` do not share the same `m_i` value as the `B` object. A `B` object has: One A base object, and two A member objects. The base object doesn't really interact with the two member objects, except as the argument in one's constructor. – jaggedSpire May 22 '15 at 19:46
  • @oneday "... and remove 53" C++ never just remove an object. It always call destructor first. – Piotr Siupa May 22 '15 at 19:47
  • Hi @jaggedSpire and NO_NAME - Thanks for the answers - I think the part I was missing was the member variables of Class B were of type class A - so when they are removed we would be calling base class - and so the output is printed - Thanks for your answers and helping me understand – oneday May 22 '15 at 19:51
0

I believe the destructors of member objects are each called after the specified destructor function, in reverse of their declaration order within the class, and then the destructors of the base objects are called.

So the order of the construction is this:

  1. Construct base class A with default value for m_i 2
  2. Construct B member m_a1 with value based on initialized m_i
  3. construct B member m_a2 with value from argument 5

and destruction is as follows:

  1. Execute destructor body for B
  2. Destruct m_a2
  3. Destruct m_a1
  4. Destruct base class A

Which translates to:

  1. print m_i
  2. decrement m_i
  3. print m_a2
  4. print m_a1
  5. print m_i
jaggedSpire
  • 4,423
  • 2
  • 26
  • 52