C++ 在C+;中使用大括号实例化对象意味着什么+;?

C++ 在C+;中使用大括号实例化对象意味着什么+;?,c++,data-structures,constructor,C++,Data Structures,Constructor,假设我有一个结构定义为: typedef struct number{ int areaCode; int prefix; int suffix; } PhoneNumber; 创建此结构的实例时,如果使用以下语法: PhoneNumber homePhone = {858, 555, 1234}; …它正在调用哪个构造函数?默认构造函数,或者复制构造函数,或者根本没有,因为它没有调用“new” 这个问题的真正目的是想知道如何添加第四个字段。因此,我想将我的结构重新定

假设我有一个结构定义为:

typedef
struct number{
    int areaCode;
    int prefix;
    int suffix;
} PhoneNumber;
创建此结构的实例时,如果使用以下语法:

PhoneNumber homePhone = {858, 555, 1234};
…它正在调用哪个构造函数?默认构造函数,或者复制构造函数,或者根本没有,因为它没有调用“new”

这个问题的真正目的是想知道如何添加第四个字段。因此,我想将我的结构重新定义为:

typedef
struct number{
    int areaCode;
    int prefix;
    int suffix;
    int extension; // NEW FIELD INTRODUCED
} PhoneNumber;
现在,我可以用四个字段创建新的PhoneNumber对象:

PhoneNumber officePhone = {858, 555, 6789, 777}
但是,我已经创建了数百个这样的PhoneNumber实例,其中只有3个字段(xxx、xxx、xxxx)。因此,我不想遍历和修改已经定义的PhoneNumber对象的每个实例化。我希望能够不使用这些字段,但仍然能够创建具有四个字段的新电话号码实例。因此,我试图找出如何覆盖构造函数,以便现有的三参数实例化不会中断,但它也将支持新的四参数实例化

当我试图定义一个覆盖默认构造函数,该构造函数包含3个字段,并将第四个字段设置为默认值“0”时,我收到错误(在代码的实例化部分,而不是构造函数定义中),抱怨我的对象必须由构造函数初始化,而不是由{…}初始化。所以,如果我重写了默认构造函数,我就不能再使用大括号来创建新对象了


对不起,如果这完全偏离了最初的问题

它实际上是在调用默认的ctor;发生的是一个结构被分配,每个值被分配使用默认的“=”。

< P> C++中的一个结构就像一个类。正在调用默认构造函数。然后,使用赋值运算符复制每个字段

成员实际上是复制初始化的。与其他一些答案所建议的相反,没有调用每个构造函数的默认构造函数,也没有涉及
操作符=
。它可以通过名为
geordi
的软件显示,或者通过阅读标准来显示。我将展示使用该软件的“有趣”方式。它有一个类
tracked::B
,可以告诉我们何时调用构造函数/复制构造函数或析构函数/复制赋值操作符。它显示的输出是(
TRACK
将跟踪限制为它后面的语句):

我用了这个密码

struct T { tracked::B b; }; int main() { tracked::B b; TRACK T t = { b };  }
如您所见,第二个
B
对象是从另一个对象
B
复制初始化的,它是局部变量
t
中的成员。当然,不会激活任何赋值运算符。如果您愿意,可以在标准中的
12.6.1/2
中阅读

顺便说一句,数组(同样也是聚合)也是如此。许多人认为作为数组成员的对象必须具有具有默认构造函数的类型。但事实并非如此。它们只需由其类型的另一个对象进行复制初始化,就可以正常工作

聚合中未显式初始化的所有其他元素都是值初始化的。值初始化是默认初始化和零初始化的混合。实际上,如果一个成员的类型具有用户声明的构造函数,则会调用该构造函数。如果它的类型没有用户声明的构造函数,那么它的每个成员都是值初始化的。对于内置类型(int、bool、指针等),值初始化与零初始化相同(这意味着这样的变量将变为零)。以下内容将每个成员初始化为零-第一个(a)除外,它将是一个:

struct T { int a, b, c; }; int main() { T t = { 1 }; }

<>这些初始化规则确实是可怕的——特别是因为C++的2003次修订引入了值初始化。它从1998年开始生效。如果您对这些括号内的初始化更感兴趣,可以阅读。

它并不像其他人所写的那样调用默认的ctor。概念上是一样的,但实际上,在汇编代码中找不到函数调用

相反,成员仍然未初始化;您正在使用大括号构造初始化它们

有趣的是,这:

PhoneNumber homePhone = {858, 555, 1234};
此组件中的结果(GCC 4.0.1,-O0):

没有多少惊喜。程序集是包含上述C++语句的函数的内联函数。值(以$开始)被移动(movl)到堆栈(ebp寄存器)的偏移量中。它们是负数,因为结构成员的内存位置在初始化代码之前

如果未完全初始化结构,即省略某些成员,如:

PhoneNumber homePhone = {858, 555};
。。。然后我得到以下汇编代码:

movl  $0, -20(%ebp)
movl  $0, -16(%ebp)
movl  $0, -12(%ebp)
movl  $858, -20(%ebp)
movl  $555, -16(%ebp)
似乎编译器实际上执行了与调用默认构造函数非常相似的操作,然后是赋值。但同样,这是在调用函数中内联的,不是函数调用

另一方面,如果您定义了将成员初始化为给定值的默认构造函数,如下所示:

struct PhoneNumber {
  PhoneNumber()
    : areaCode(858)
    , prefix(555)
    , suffix(1234)
  {
  }

  int areaCode;
  int prefix;
  int suffix;
};

PhoneNumber homePhone;
然后获得实际调用函数的汇编代码,并通过指向结构的指针初始化数据成员:

movl  8(%ebp), %eax
movl  $858, (%eax)
movl  8(%ebp), %eax
movl  $555, 4(%eax)
movl  8(%ebp), %eax
movl  $1234, 8(%eax)
每行进入
movl8(%ebp),%eax
设置指向结构数据开头的指针值(eax寄存器)。在其他行中,eax直接使用,偏移量为4,偏移量为8,类似于前两个示例中的直接堆栈寻址

当然,所有这些都是特定于编译器实现的,但是如果其他编译器做了一些非常不同的事情,我会感到惊讶

然而,我有几百个这样的 PhoneNumber实例已创建 只有3个字段(xxx、xxx、xxxx)。 所以我不想经历 修改的每个实例 我的PhoneNumber对象已存在 定义

没问题,您只需为重新定义的类调用更新实例,然后。。。。。呃,没关系。继续标记此“无帮助”

Ini
struct PhoneNumber {
  PhoneNumber()
    : areaCode(858)
    , prefix(555)
    , suffix(1234)
  {
  }

  int areaCode;
  int prefix;
  int suffix;
};

PhoneNumber homePhone;
movl  8(%ebp), %eax
movl  $858, (%eax)
movl  8(%ebp), %eax
movl  $555, 4(%eax)
movl  8(%ebp), %eax
movl  $1234, 8(%eax)