构造函数-C ++默认构造函数

例如,当我不声明constructor时,编译器将为我提供default constructor,它没有参数也没有定义(正文),因此将不采取任何措施。

如果我现在不声明default constructor,则编译器将为我提供default destructor没有定义(body),因此,我认为不采取任何措施。

因此,例如,如果我完成了一个对象,那么default constructor不会重新分配该对象使用的(空闲)内存吗? 如果没有,我们为什么要得到它?

并且,也许相同的问题也适用于default constructor。如果它什么也不做,为什么默认情况下会为我们创建它?

谢谢。

7个解决方案
67 votes

说编译器生成的默认构造函数不执行任何操作是错误的。 它等效于具有空主体和空初始化列表的用户定义构造函数,但这并不意味着它不采取任何措施。 这是它的作用:

  1. 它调用基类的默认构造函数。
  2. 如果类是多态的,它将初始化vtable指针。
  3. 它调用所有拥有它们的成员的默认构造函数。 如果某个成员具有某些构造函数,但没有默认构造函数,则为编译时错误。

并且只有当一个类不是多态的,没有基类并且没有需要构造的成员时,编译器生成的默认构造函数才会执行任何操作。 但是即使这样,出于其他答案中所述的原因,有时有时也需要默认构造函数。

析构函数也是如此-它调用基类的析构函数以及所有拥有它们的成员的析构函数,因此在一般情况下,编译器生成的析构函数不执行任何操作都是不正确的。

但是内存分配确实与此无关。 内存是在调用构造函数之前分配的,只有在最后一个析构函数完成之后才释放内存。

Sergei Tachenov answered 2020-02-14T10:58:18Z
5 votes

因为如果您没有任何(可公共访问的)构造函数或析构函数,则无法实例化该类的对象。 考虑:

class A
{
private:
    A() {}
    ~A() {}
};

A a;  // Oh dear!  Compilation error

如果没有显式声明任何构造函数或析构函数,则编译器必须提供一个允许创建对象的构造函数。

Oliver Charlesworth answered 2020-02-14T10:58:42Z
4 votes

默认的析构函数不会做任何事情(就像默认的构造函数一样)。

如果您的析构函数实际上需要做某事(例如:释放一些资源),则需要自己定义。

请注意,通常应遵循以下三个规则:如果程序需要在其析构函数中执行某些操作(例如:释放资源),则还应提供一个拷贝构造函数和一个赋值运算符; C ++还提供了它们的默认版本(同样,它什么也不做)。

当您处理不需要做任何事情的简单类时,默认构造函数/析构函数/赋值运算符/副本构造函数非常有用。 POD是一种特殊情况:它们(在C ++ 0x之前)甚至不能具有显式构造函数或析构函数。

peoro answered 2020-02-14T10:59:16Z
4 votes

默认构造函数和析构函数只是一种商品,以防您不需要对类进行任何特殊处理而无需手动编写空版本的情况。 这在其他OO语言中很常见,例如在Java中,如果成员的零初始化就足够了,则无需提供构造函数。 同时,这是与C向后兼容的要求。如果您在C中具有struct,则它将没有构造函数或析构函数(C没有这些概念),以便能够在C ++中处理该代码, 是有效的代码。

另一个选择是用该语言声明一个类可以没有构造函数或析构函数,但是整个语言规范将不得不处理这样一个事实,即某些类型可能具有构造函数和析构函数,而其他类型则没有,这将使 语言更加复杂且难以指定。 虽然具有隐式定义的版本不会更改行为,但可以简化规范。

在此级别上,就像术语“替代程序”被应用于基类中的方法。 在基类中,它不覆盖任何内容,没有任何内容可以覆盖! 然而,该语言明确指出,在基中声明的虚拟非纯方法是替代程序。 这使规范可以简单地说,当通过指针或引用调用该方法时将调用最终的重写器,而无需在该特定层次结构中不存在用于该特定方法的替代器的情况下添加外部或基本方法实现。

David Rodríguez - dribeas answered 2020-02-14T10:59:48Z
2 votes

使用智能指针时,默认析构函数(请参见Sergey的答案)对于避免内存泄漏至关重要。 这里有个例子:

#include <iostream>
#include <memory>

using namespace std;

class Foo {
public:
  Foo(int n = 0): n(n) { cout << "Foo(" << n << ")" << endl; }
  ~Foo() { cout << "~Foo(" << n << ")" << endl; }
private:
  int n;
};

// notes:
// * default destructor of Bar calls destructors of unique_ptr<Foo> foo
//  and of unique_ptr<Foo[]> foo3, which, in turn, delete the Foo objects
// * foo2's Foo object leaks
class Bar {
public:
  Bar(): foo(new Foo(1)), foo2(new Foo(2)), foo3(new Foo[2]) { }
private:
  unique_ptr<Foo> foo;
  Foo* foo2;
  unique_ptr<Foo[]> foo3;
};

int main() {
  Bar bar;
  cout << "in main()" << endl;
}

此处的输出显示仅foo2发生泄漏:

Foo(1)
Foo(2)
Foo(0)
Foo(0)
in main()
~Foo(0)
~Foo(0)
~Foo(1)
Ulrich Stern answered 2020-02-14T11:00:13Z
1 votes

简短的答案是,在C ++中,每个对象都需要一个构造函数和一个析构函数,即使它们什么都不做。 因此,在后台为您创建它们的编译器可以满足此要求。

更长的答案是,构造函数负责类成员的初始化。 默认构造函数对所有成员进行默认初始化。 (对于POD类型,这并不意味着什么,但是其他类将调用其默认构造函数。)

SoapBox answered 2020-02-14T11:00:38Z
0 votes

默认的析构函数将无法知道您的类拥有“什么”内存才能释放它。

至于默认的构造函数部分,我将在这一部分引用Wikipedia文章...

在C ++中,默认构造函数很重要,因为它们是   在某些情况下自动调用   情况:

  • 如果声明的对象值没有参数列表,例如 我的课   X;; 或没有动态分配   参数列表,例如 新的MyClass; 的   默认构造函数用于   初始化对象
  • 当声明一个对象数组时,例如 MyClass x [10] ;; 要么   动态分配,例如 新   MyClass [10]; 默认构造函数   用于初始化所有元素
  • 当派生类构造函数未显式调用基数时   初始化程序中的类构造函数   列表,默认的构造函数   基类被称为
  • 当类构造函数未显式调用的构造函数时   它的对象值字段之一   初始化列表,默认   该字段的类的构造函数是   叫
  • 在标准库中,某些容器使用   值为时的默认构造函数   没有明确给出,例如   向量(10); 初始化   具有10个元素的向量   充满默认构造   我们类型的价值。

在上面   在这种情况下,如果   类没有默认值   构造函数。 编译器将   隐式定义一个默认值   建设者

如果没有构造函数   为类明确定义。 这个   隐式声明的默认值   构造函数等效于默认值   用空白主体定义的构造函数。   (注意:如果某些构造函数是   定义,但它们都是非默认值,   编译器不会隐式地   定义一个默认的构造函数。 这个   表示默认构造函数可以   某个班级不存在。)

Andrew White answered 2020-02-14T11:01:40Z
translate from https://stackoverflow.com:/questions/4837223/c-default-destructor