【问题标题】:What happens inside of a C++ constructor?C++ 构造函数内部发生了什么?
【发布时间】:2019-12-28 22:07:11
【问题描述】:

我想知道在 C++ 中调用类的构造函数时会发生什么。更具体地说,调用了哪些其他函数,以及如何调用。如果使用new,它是调用一些内置函数在堆栈上构造对象,还是调用malloc在堆上构造它?是否使用了默认分配器?

一般来说,不调用构造函数就可以使用类和对象吗?

编辑:一个很好的问题可能有助于我想要解决的问题,是:为什么构造函数不返回任何东西?最初,我认为新手程序员会期望构造函数返回对象,但事实并非如此。会发生什么?

【问题讨论】:

  • 不存在“调用构造函数”的语法。请举例说明您的意思。
  • @LightnessRacesBY-SA3.0 可以说placement-new 实际上是一个构造函数调用。
  • @LightnessRacesBY-SA3.0 我的意思是“auto x = X()”的结尾,其中 X 是类的名称。
  • @AnthonyMonterrosa 啊,一个常见的误解。那不是“调用构造函数”。我知道您似乎正在调用一个名为 X 的函数,但您不是。构造函数的调用是为您完成的,隐藏在机械层后面;你在那里做的是使用功能转换符号来请求创建一个临时类型的X
  • @HolyBlackCat 因为它不是一个。它的位置新。它开始了对象的生命周期。其中一部分可能涉及构造函数的[自动]调用等。构造函数不是创建对象的东西。构造函数是一个可选的额外功能,它执行一些对象创建后的任务。

标签: c++ constructor allocation


【解决方案1】:

为什么构造函数不返回任何东西?

构造函数不返回对象,它在一块内存上构造对象,并且不管该内存是如何分配的。如果您将完成的对象视为建筑物,那么构造函数就是在给定的土地上建造建筑物的功能。购买土地不是建设者的工作,只是在上面建造(建造)。

返回对象的构造函数将无法构造分配在堆栈上或嵌入其他对象的对象。相反,分配和构造是分离的,构造函数有效地接收指向它应该工作的内存的指针(暴露为this 指针)。这样,相同的构造函数适用于堆栈和堆分配的对象。

【讨论】:

  • 你能写出与返回指针的构造函数具有相同功能的函数吗?
  • @AnthonyMonterrosa 如果您正在寻找一种完全跳过构造函数调用的方法,那么 C++ 似乎并未正式支持,如另一个答案的 cmets 中所述。了解更多关于您实际想要实现的目标的详细信息会有所帮助。
【解决方案2】:

在 C++ 中调用类的构造函数时会发生什么。更具体地说,调用了哪些其他函数

类成员被初始化。如果某些成员是类实例,则调用它们的构造函数。

如果有的话,还会调用基类的构造函数。

是调用一些内置函数在栈上构造对象,还是调用malloc在堆上构造对象,如果使用new

为类实例分配内存不是构造函数的工作。调用者会这样做。

例如如果您使用new-表达式,它会分配内存(通过operator new),然后调用该内存上的构造函数。

是否可以在不调用构造函数的情况下使用类和对象?

使用aggregate initialization 创建类实例不会调用构造函数。

您也可以使用类而不创建对象(即与静态成员交互)。


编辑:为什么构造函数不返回任何东西?

构造函数有效地接收一个地址,并在该地址构造一个实例。它不需要返回那个地址,因为它是由调用者开始提供的。

这就是 C++ 的工作原理。

它还能如何工作?假设您想从构造函数返回一个对象。这是否意味着在构造函数中分配临时存储,在其中构造一个对象,然后让调用者从该存储中复制对象?这将需要一个工作副本构造函数。但是复制构造函数本身是如何实现的呢?

【讨论】:

  • 抱歉,“是否可以在不调用构造函数的情况下使用类和对象?”我的意思是在不使用构造函数的情况下具有与构造函数等效的功能的代码是什么。这个问题是针对教学法提出的。
  • @AnthonyMonterrosa 您可以创建一个函数来执行构造函数通常所做的任何事情(通过在每个成员上调用 placement-new 来初始化类成员),但是您不能做一件事:您可以t begin the lifetime of the object(没有实际调用构造函数或进行聚合初始化)。
  • “开始生命”是一个抽象的概念。即使构造函数绝对什么都不做,您仍然必须调用它以使对象生命周期“开始”。使用不在其生命周期内的对象在技术上是未定义的行为,并且可能会或可能不会发生坏事。 (它们更有可能发生在发布版本中。)
  • 那么是否可以创建手动构造函数?看起来不像,考虑到必须使用非手动构造函数来启动对象的生命周期。
  • @AnthonyMonterrosa 是的,正式来说这是不可能的。在实践中,在某些情况下,您也许可以避免不开始生命周期,尤其是在禁用编译器优化的情况下。
【解决方案3】:

Class 由用户定义,它包含方法和属性... Object 是由构造函数创建的Class 的一个实例。

所以new 操作符调用构造函数并分配内存,它返回一个指针。 new 运算符分配内存。

让我们创建一个Class,没有内存分配:

Class A {
       A(); //User Constructor
};
 Class B {
 private:
 std::string _name;
}; 

` 让我们用 new 创建一个指向 Object A 的指针

A *a = new A(); //Call the user defined constructor with memory allocation return a pointer of A

另一种方法是实例化一个没有new的对象

A a; //call the user defined constructor.
B b; //call the default constructor

构造函数的作用是创建一个对象。 C++ 有一个默认构造函数,如果用户没有创建构造函数,它会被隐式调用。

【讨论】:

  • @walnut 你会考虑如何分配内存?告诉系统保留地址间隔?
  • @AnthonyMonterrosa Allocation 正在获取一个指向内存块的指针,该内存块可用于将给定大小(和对齐)的对象放入其中,而不会干扰其他对象的内存。对象本身是由构造函数构造到这个内存中的。动态分配是operator new 的工作。自动和静态存储持续时间变量的分配是编译器的工作(例如通过堆栈布局)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-09
  • 1970-01-01
  • 2021-09-11
  • 2018-01-01
  • 2011-04-16
相关资源
最近更新 更多