gpt4 book ai didi

c++ - C++中的List初始化、Initializer_list及相关问题

转载 作者:行者123 更新时间:2023-11-30 05:08:48 27 4
gpt4 key购买 nike

我知道这是一个在 stackoverflow 上被广泛讨论的主题,但我很难找到彻底的答案来消除我对 C++ 中的列表初始化和 initializer_lists 的所有困惑,所以我会试一试并提出我自己的问题。

请考虑以下代码片段:

class C
{
public :
C(int a, int b, int c) : _a (a), _b(b), _c(c) {}; //initialization_list with ()
//C(int a, int b, int c) : _a{ a }, _b{ b }, _c{ c } {}; //initialization list with {}
private :
int _a, _b, _c;
};

int main()
{
C a(5.3,3.3,4.3); // no list
C b{5.3,3.3,4.3}; // list {}
C c({5.3,3.3,4.3}); // list {}
}

我不明白为什么这两个初始化列表的行为相似?我原以为,当尝试使用 _a{a}, _b{b}, _c{c} 类型的初始化列表创建 C 类型的对象时,会出现有关缩小的编译器错误。但是,不会生成任何错误,_a、_b 和 _c 仅存储整数值。

只有在使用列表“{}”创建对象 b 或 c 时,编译器才会生成缩小错误消息。这是为什么?使用我不知道的 {} 或 () 编写初始化列表之间是否存在任何差异,或者行为是否相同?

我的下一个问题:

class C
{
public :

//private :
int _a, _b, _c;
};

int main()
{
C a(5,3,4); //obviously doesn't work as no such constructor
C b{5,3,4}; //work only if _a, _b and _c are not private nor protected!
}

为什么第二个语句(带大括号)只有在变量是公共(public)的情况下才有效?涉及的机制是什么?

所以我想更好地理解,除了通过创建一个带有列表 {} 的对象所提供的“缩小安全性”之外,这个列表还有哪些其他“功能”机制提供?因为在第二次调用中,调用的仍然是默认构造函数(因此,不是以 initializer_list 作为参数的默认构造函数),对吧?

最后,想象一下在我的 C 类 中,我有另一个构造函数将初始化列表作为参数。

class C
{
public :
C() = default; //default constructor
C(int a, int b, int c) : _a (a), _b(b), _c(c) {};
C(std::initializer_list<int> a) { //do some stuffs with the list};
private :
int _a, _b, _c;
};

很明显,如果尝试创建一个接受除 3(或实际上为 0)以外的任意整数的对象,将调用采用 initializer_list 的构造函数。但是,如果创建这样的对象:

C c();

C c{};

将调用默认构造函数。但是如果创建一个恰好有 3 个整数的对象:

C c(5,2,3);

C c{5,2,3};

将调用 initializer_list 构造函数。规则是这样的:

  • If either a default constructor or an initializer-list constructor could be invoked, prefer the default constructor
  • If both an initializer-list contructor and an "ordinary constructor" could be invoked, prefer the initializer-list constructor

因此(如果我错了请纠正我),如果我这样创建我的对象:

C c{5,3,4};

将调用 initializer-list 构造函数。但是,如果我这样创建我的对象:

C c(5,3,4);

将调用第二个构造函数(以 3 个整数作为参数)。我的问题是:如果我也想提供缩小安全性,我如何使用第二个构造函数而不是初始化列表构造函数创建对象? (因为如果我像这个问题的第一个例子那样做,初始化列表构造函数将被调用!)。

请不要犹豫,举例说明您的回复,并讨论我在这个问题中没有谈到的与列表相关的概念。我想很好地掌握这些。谢谢。

最佳答案

因此,无论何时使用大括号,您都在使用 aggregate initialization ,一种按顺序或通过指示符初始化的结构或类的初始化方法。例如,

#include <iostream>

struct Foo
{
int a;
char b;
};

class Doo
{
public:
double h;
char ch;
};

int main() {
Foo first = {3, 't'};
std::cout << first.b << "\n";
//t
Doo second = {'3', 50};
std::cout << second.ch << "\n";
//2 interpreted as char
}

在这里,当我们使用 {} 初始化一个类或结构时,它们总是被解释为在类中列出的顺序。这就是打印“2”的原因,因为 ASCII 中的 50 对应于字符“2”。

构造函数初始化

因此您也可以对构造函数初始化列表使用相同的逻辑,

#include <iostream>

struct Pair
{
int first;
long second;
};

class Couple
{
public:
Pair p;
int g;
public:
Couple(): p{3, 700}, g{3}
{}
};

int main() {
Couple test;
std::cout << test.p.first << "\n";
//3
}

此处,p 旁边的 {3, 700}Pair p = {3, 700}; 相同在代码中的其他地方使用。您基本上使用有序聚合初始化。现在,如果我们将 Pair 字段的花括号更改为圆括号会怎样?

我们得到这个错误

main.cpp: In constructor 'Couple::Couple()':
main.cpp:15:26: error: no matching function for call to 'Pair::Pair(int, int)'
Couple(): p(3, 700), g{3}

那是因为我们没有接受两个数字的 Pair 的构造函数。因此,聚合初始化和括号之间的主要区别在于,您需要为使用括号创建的任何特定参数集实现构造函数,而使用大括号,您可以只使用编译器提供给您的默认值。

std::initializer_list 是一种不常用的容器形式,用于使用 {} 初始化列表中的多个参数。

关于c++ - C++中的List初始化、Initializer_list及相关问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46569038/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com