构造函数在必须创建另一个类的新对象时是如何工作的

how constructor work when it has to create a new object of an other class?

本文关键字:何工作 工作 对象 另一个 创建 构造函数 新对象      更新时间:2023-10-16

我有这个代码,我试图了解编译器是如何工作的:

#include <iostream>
using namespace std;
class Block
{
    int data;
public:
    Block(int i = 10)
        : data(i)
    { 
        cout << "I just created a Block " << endl;
    }
    ~Block()
    {
        cout << "I will destroy a Block with " << data << endl;
    }
    void inc()
    {
        data++;
    }
};
class A
{
    Block& block1;
    Block block2;
public:
    A(Block& blk)
        : block1(blk)
        , block2(blk)
    {
        cout << "I just created an A " << endl;
    }
    A(const A& a)
        : block1(a.block1)
        , block2(a.block2)
    {
        cout << "I just created an A by copying but I will also do bad things" << endl;
        block1.inc();
        block2.inc();
    }
    ~A()
    {
        cout << "I will destroy an A " << endl;
    }
    void inc()
    {
        block1.inc();
        block2.inc();
    }
};
class Fat
{
    A a;
    A& ra;
    A* pa;
public:
    Fat(A& da)
        : a(da)
        , ra(da)
    {
        pa = new A(da);
        cout << "Fat just created !" << endl;
    }
    ~Fat()
    {
        delete pa;
        cout << "Fat to be destroyed !" << endl;
    }
    void inc()
    {
        a.inc();
        ra.inc();
        pa->inc();
    }
};
int main()
{
    Block block;
    A a(block);
    Fat fat(a);
    fat.inc();
    return 0;
}

当它创建一个A对象时,是创建一个新的块还是使用现有的块?为什么不运行block的构造函数?

程序的输出是:

I just created a Block 
I just created an A 
I just created an A by copying but I will also do bad things
I just created an A by copying but I will also do bad things
Fat just created !
I will destroy an A 
I will destroy a Block with 12
Fat to be destroyed !
I will destroy an A 
I will destroy a Block with 12
I will destroy an A 
I will destroy a Block with 11
I will destroy a Block with 15

您可以用更简单的代码来演示。

#include <iostream>
class Noisy
{
public:
    Noisy()
        { std::cout << "Noisy default constructn"; }
    ~Noisy()
        { std::cout << "Noisy destroyn"; }
};
int main()
{
    Noisy noisy1;
    Noisy noisy2(noisy1);
}

输出<>之前嘈杂的默认构造嘈杂的破坏嘈杂的破坏之前

注意,显然,只构造了一个对象,但销毁了两个对象。出现这种明显不一致的原因是因为我们没有记录所有的构造函数。这里有一个隐式生成的复制构造函数,我们使用它在这一行中构造noisy2:

Noisy noisy2(noisy1);

如果我们自己定义复制构造函数,

#include <iostream>
class Noisy
{
public:
    Noisy()
        { std::cout << "Noisy default constructn"; }
    Noisy(Noisy const&)
        { std::cout << "Noisy copy constructn"; }
    ~Noisy()
        { std::cout << "Noisy destroyn"; }
};
int main()
{
    Noisy noisy1;
    Noisy noisy2(noisy1);
}
输出:

<>之前嘈杂的默认构造噪声复制构造嘈杂的破坏嘈杂的破坏之前

可以看到两个对象被构造了,只是用了不同的构造函数。如果对不同的类这样做,应该会看到类似的结果。你的引用不会被记录,无论是构造函数还是析构函数,因为它们不是对象。

当它创建一个A对象时,是创建一个新的块还是使用现有的块?为什么不运行block的构造函数?

查看A构造器:

A(Block& blk)
        : block1(blk)
        , block2(blk)
    {
    }

block1是对Block对象的引用。所以它引用已经创建的blk变量,它不会创建另一个。所以在这种情况下没有调用构造函数。

对于不是引用的block2来说,这不是真的。在这种情况下,确实创建了一个new对象Block,但使用复制构造函数。

Block类中定义的是一个默认构造函数。当从同一类的另一个对象开始创建类实例时,将调用复制构造函数(注意:不是默认构造函数)。

复制构造函数由编译器隐式定义,除非你自己定义。

例如:

class Block {
 public:
   Block(const Block& other) : data(oth.data) {
     std::cout << "Invoked copy 'ctor" << std::endl;
   }
   // ... other stuff
};

这就是为什么您的代码只调用一次类Block默认构造函数