Yair
Yair

Reputation: 85

C++ - How does initializing and desctruction works?

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.

Upvotes: 0

Views: 245

Answers (3)

HatsuPointerKun
HatsuPointerKun

Reputation: 637

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 )

Upvotes: 3

mco
mco

Reputation: 85

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)

Upvotes: 1

Basti Funck
Basti Funck

Reputation: 1439

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.

Upvotes: 2

Related Questions