0

I wrote the following code (the classes were written in separate .h files):

class A
{

public:
    A(){
        cout << "This is the constructor of A!" << endl;
        foo();
    }
    virtual ~A(){
        cout << "Destroyed A type" << endl;
    }

    virtual void foo();
};

void A::foo()
{
    cout << "foo()::A" << endl;
}

class B: public A
{

public:
    B(){}
    ~B(){
        cout << "Destroyed B type" << endl;
    }

    void foo();
};

void B::foo()
{
    cout << "foo()::B" << endl;
}

And the following main function:

int main()
{
    A b = B();
    A *bp = &b;
    A &ra = b;

    bp->foo();
    ra.foo();

    return 0;
}

When I run it, I get the following output:

This is the constructor of A!
foo()::A
Destroyed B type
Destroyed A type
foo()::A
foo()::A
Destroyed A type

My question is - why does B() is being destroyed immediately? doesn't b suppose to point to it, to be a B type object? How to I initialize b to be a new B? Maybe I am confused with Java, there we would say the static type of b is A and the dynamic type is B. Isn't that the same situation here? I would love the understand the mechanism behind this code.

Yair
  • 85
  • 1
  • 9
  • 2
    *Maybe I am confused with Java* - you bet!! – rustyx Oct 30 '17 at 20:02
  • 1
    `A b = B();` This line of code creates an object. And the thing on the right side of the `=` also creates an object. – David Schwartz Oct 30 '17 at 20:03
  • 1
    I highly recommend searching StackOverflow for "C++ initialization constructor destructor" as there are already a plethora of posts on this topic. – Thomas Matthews Oct 30 '17 at 20:03
  • 1
    Try explaining this line to your [rubber duck](https://en.wikipedia.org/wiki/Rubber_duck_debugging): `A b = B();`. – juanchopanza Oct 30 '17 at 20:04
  • Can you add some trace statement to B constructor to see if the A b = B(); creates a class of A type, that calls a class of B type, then destroys B, then destroy A? – A.Rashad Oct 30 '17 at 20:18
  • I second @RustyX: The line `A b = B()` means something radically different in C++ than the line `A b = new B()` in java. The difference is, that C++ can talk about variables containing objects, while java can only talk about variables containing pointers to objects. In C++ the pointers have to be explicit as in `A* b = new B()`. – cmaster - reinstate monica Oct 30 '17 at 20:28

3 Answers3

3

why does B() is being destroyed immediately?

On this line :

A b = B();

You do several things. Here are the steps :

  • You create a temporary value of type B, which calls the default base class constructor, which output that :

    This is the constructor of A!
    foo()::A
    

    Then calls the default constructor of B

  • After that, a object of type A is created, and the compiler generated copy constructor with A parameter ( A(const A& a) ) is called, and slices the temporary value. ( by the way, you should follow the rule of three )

  • Then, the temporary value is destroyed, and since it's a value of type B, it calls the B destructor first, and then the A destructor which is the reason why you get that :

    Destroyed B type
    Destroyed A type
    

doesn't b suppose to point to it, to be a B type object?

No, not at all. b is not a pointer to a A object, it's a A value type.

How to I initialize b to be a new B

It's a value type, so you can't be a "B type", because of object slicing. If you don't know what is object slicing, you should read that : What is object slicing ?

Maybe I am confused with Java

Yes.

there we would say the static type of b is A and the dynamic type is B. Isn't that the same situation here?

In java, it is. In C++, if you want to do the same thing, you need to do that :

A* b = new B();

Here, the static type of b is A, but it points to a B object. Of course, don't forget to free the memory after you used it, like this :

delete b;

since C++ won't manage memory for you. Or better : use smart pointers.

I have another question please: what happens in this line: "A &ra = b;"?

A reference type to A called ra is created, and references the object b

What is ra exactly?

ra is a a reference type to A. See there

I understand it's type is A but what happens behind the scenes? for example, when I tried "A a = b;" an A object was created. This is not the case with ra, yet ra is an A object (for example, if we will make foo() not virtual, it will choose the foo of A). Do you know to explain this?

No, no, no. ra type is a reference type to A, not a A value type

A reference type is basically an alias, another name for a value. As explained in this tutorial :

C++ references allow you to create a second name for the a variable that you can use to read or modify the original data stored in that variable. While this may not sound appealing at first, what this means is that when you declare a reference and assign it a variable, it will allow you to treat the reference exactly as though it were the original variable for the purpose of accessing and modifying the value of the original variable--even if the second name (the reference) is located within a different scope. This means, for instance, that if you make your function arguments references, and you will effectively have a way to change the original data passed into the function.


In you case, ra is a reference type which references to the object b, so ra is another name for the object b. So when you do ra.foo(), it is the exact same thing as b.foo(), since ra reference the object b, references the same data in memory.

Behind the scene, it's generally implemented using a pointer ( see this SO answer ). Maybe in your case, it can be simply removed ( i don't know, i tried to look at the assembly file, but it's hard to read )

HatsuPointerKun
  • 637
  • 1
  • 5
  • 14
  • Thanks :), I will read about the slicing and look up that copy constructor and smart pointers – Yair Oct 30 '17 at 21:03
  • I have another question please: what happens in this line: "A &ra = b;"? What is ra exactly? I understand it's type is A, but what happens behind the scenes? for example, when I tried "A a = b;" an A object was created. This is not the case with ra, yet ra is an A object (for example, if we will make foo() not virtual, it will choose the foo of A). Do you know to explain this? (I searched but didn't know how to find similiar examples) – Yair Nov 01 '17 at 20:29
2

B() creates an object of type B, A b = B() then copies the created object into the variable b. At this point 2 objects exists, one temporary object of type B that gets deleted after the copying, and one object of type A, because your B object got sliced after copying into b.

Basti Funck
  • 1,400
  • 17
  • 31
  • 2
    Not really two instances of `B`. The copy is an instance of `A`. – Sebastian Oct 30 '17 at 20:09
  • Thats true, `B` instance gets sliced into an `A` instance. – Basti Funck Oct 30 '17 at 20:13
  • Why does it get sliced? and why later on It is treated as an A type instead of a B type (as you can see, only the foo() method of A is being called)? – Yair Oct 30 '17 at 20:25
  • 1
    What happens is with `A b` you reserve space on the stack to store an object of type `A`. But when you copy an object of type `B` into that everything thats not part of type `A` gets cutoff. What you want to achieve is polymorphism which you can do with pointers. `A* b = new B()` would allocate an object of type `B` on the heap and then store the address in `b`. Now nothing gets cutoff and your `A*` points to a `B` object. But don't forget to `delete` the object when finished using it. I advice having a look on how *pointers* work and what *smartpointers* are. – Basti Funck Oct 30 '17 at 20:41
1

When you compile this source, compiler automatically generates an copy constructor operator for both A and B classes. When A b = B(); is executed, the following happens:

  1. A temporary instance of B is created by constructor B::B().
  2. Auto generated copy constructor of A is called. This constructs instance b from the temporary instance B generated at step 1.
  3. Temporary object created at step 1 is destroyed. (This is where B::~B() is called)
mco
  • 83
  • 7