C++ - 初始化和销毁​​是如何工作的?

C++ - How does initializing and desctruction works?

我写了以下代码(类 写在单独的 .h 文件中):

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;
}

以及以下主要函数:

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

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

    return 0;
}

当我 运行 它时,我得到以下输出:

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

我的问题是 - 为什么 B() 会立即被销毁? b 不应该指向它,成为 B 类型的对象吗?如何将 b 初始化为新 B?可能我和Java搞混了,那里会说b的静态类型是A,动态类型是B,这里不也是一样的情况吗?我很想了解这段代码背后的机制。

B() 创建类型为 B 的对象,A b = B() 然后将创建的对象复制到变量 b 中。此时存在 2 个对象,一个 B 类型的临时对象在复制后被删除,一个 A 类型的对象,因为你的 B 对象在复制到 b.

编译此源代码时,编译器会自动为 AB 类 生成复制构造函数运算符。当执行 A b = B(); 时,会发生以下情况:

  1. B 的临时实例由构造函数 B::B() 创建。
  2. 调用了 A 的自动生成的复制构造函数。这从第 1 步生成的临时实例 B 构造实例 b
  3. 在步骤 1 中创建的临时对象已销毁。 (这是调用 B::~B() 的地方)

why does B() is being destroyed immediately?

这一行:

A b = B();

你做几件事。以下是步骤:

  • 你创建了一个类型 B 的临时值,它调用默认的基础 class 构造函数,输出:

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

    然后调用B的默认构造函数

  • 之后,创建一个A类型的对象,调用编译器生成的带A参数的拷贝构造函数(A(const A& a)),并切片临时值。 (顺便说一句,你应该遵循 the rule of three

  • 然后,临时值被销毁,因为它是一个B类型的值,它首先调用B析构函数,然后是A析构函数,这就是你得到的原因那:

    Destroyed B type
    Destroyed A type
    

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

不,一点也不。 b 不是指向 A 对象的指针,它是 A 值类型。

How to I initialize b to be a new B

它是一个值类型,所以你不能是 "B type",因为对象切片。如果你不知道什么是对象切片,你应该阅读:What is object slicing ?

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?

在java中是。在 C++ 中,如果你想做同样的事情,你需要这样做:

A* b = new B();

这里b的静态类型是A,但是指向了一个B对象。当然,不要忘记在使用后释放内存,像这样:

delete b;

因为 C++ 不会为您管理内存。或者更好:使用智能指针。

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

创建了一个名为 raA 引用类型,并引用了对象 b

What is ra exactly?

ra 是 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?

不不不。 ra 类型是 A 的引用类型,而不是 A 值类型

引用类型基本上是一个别名,是值的另一个名称。如 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.


在你的例子中,ra 是引用对象 b 的引用类型,因此 ra 是对象 b 的另一个名称。因此,当您执行 ra.foo() 时,它 b.foo() 完全相同 ,因为 ra 引用对象 b,引用内存中的相同数据。

在幕后,它通常是使用指针 (see this SO answer) 实现的。也许在你的情况下,它可以简单地删除(我不知道,我试图查看汇编文件,但很难阅读)