文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C++聚合体初始化的方法是什么

2023-07-05 02:05

关注

本篇内容介绍了“C++聚合体初始化的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

聚合体初始化(aggregate initialization)

C++有很多初始化对象的方法。其中之一叫做 聚合体初始化(aggregate initialization) ,这是聚合体专有的一种初始化方法。

从C语言引入的初始化方式是用花括号括起来的一组值来初始化类:

struct Data {    std::string name;    double value;};Data x = {"test1", 6.778};

自从C++11起,你可以忽略等号:

Data x{<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->"test1", 6.778};

自从C++17起,聚合体可以拥有基类。也就是说像下面这种从其他类派生出的子类也可以使用这种初始化方法:

struct MoreData : Data {    bool done;}MoreData y{{"test1", 6.778}, false};

如你所见,聚合体初始化时可以用一个子聚合体初始化来初始化类中来自基类的成员。

另外,你甚至可以省略子聚合体初始化的花括号:

MoreData y{<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->"test1", 6.778, false};

这样写将遵循嵌套聚合体初始化时的通用规则,你传递的实参被用来初始化哪一个成员取决于它们的顺序。

扩展聚合体初始化的动机

如果没有这个特性,那么所有的派生类都不能使用聚合体初始化,这意味着你要像下面这样定义构造函数:

struct Cpp14Data : Data {    bool done;    Cpp14Data (const std::string& s, double d, bool b) : Data{s, d}, done{b} {    }};Cpp14Data y{"test1", 6.778, false};

现在我们不再需要定义任何构造函数就可以做到这一点。

我们可以直接使用嵌套花括号的语法来实现初始化,

如果给出了内层初始化需要的所有值就可以省略内层的花括号:

MoreData x{{"test1", 6.778}, false};    // 自从C++17起OKMoreData y{"test1", 6.778, false};      // OK

注意因为现在派生类也可以是聚合体,所以其他的一些初始化方法也可以使用:

MoreData u;     // OOPS:value/done未初始化MoreData z{};   // OK: value/done初始化为0/false

如果觉得这样很危险,可以使用成员初始值:

struct Data {    std::string name;    double value{0.0};};struct Cpp14Data : Data {    bool done{false};};

或者,继续提供一个默认构造函数。

使用聚合体扩展

聚合体初始化的一个典型应用场景是对一个派生自C风格结构体并且添加了新成员的类进行初始化。例如:

struct Data {    const char* name;    double value;};struct CppData : Data {    bool critical;    void print() const {        std::cout << '[' << name << ',' << value << "]\n";    }};CppData y{{"test1", 6.778}, false};y.print();

这里,内层花括号里的参数被传递给基类Data

注意你可以跳过初始化某些值。在这种情况下,跳过的成员将会进行默认初始化

(基础类型会被初始化为0false或者nullptr,类类型会默认构造)。

例如:

CppData x1{};           // 所有成员默认初始化为0值CppData x2{{"msg"}}     // 和{{"msg", 0.0}, false}等价CppData x3{{}, true};   // 和{{nullptr, 0.0}, true}等价CppData x4;             // 成员的值未定义

注意使用空花括号和不使用花括号完全不同:

x1的定义会把所有成员默认初始化为0值,

因此字符指针name被初始化为nullptr

double类型的value初始化为0.0

bool类型的flag初始化为falsex4的定义没有初始化任何成员。所有成员的值都是未定义的。

你也可以从非聚合体派生出聚合体。例如:

struct MyString : std::string {    void print() const {        if (empty()) {            std::cout << "<undefined>\n";        }        else {            std::cout << c_str() << '\n';        }    }};MyString x{{"hello"}};MyString y{"world"};

注意这不是通常的具有多态性的public继承,因为std::string没有虚成员函数,

你需要避免混淆这两种类型。

你甚至可以从多个基类和聚合体中派生出聚合体:

template<typename T>struct D : std::string, std::complex<T>{    std::string data;};

你可以像下面这样使用和初始化:

D<float> s{{"hello"}, {4.5, 6.7}, "world"}; // 自从C++17起OKD<float> t{"hello", {4.5, 6.7}, "world"};   // 自从C++17起OKstd::cout << s.data;                        // 输出:"world"std::cout << static_cast<std::string>(s);   // 输出:"hello"std::cout << static_cast<std::complex<float>>(s);   //输出:(4.5,6.7)

内部嵌套的初值列表将按照继承时基类声明的顺序传递给基类。

这个新的特性也可以帮助我们用很少的代码定义重载的lambda

聚合体的定义

总的来说,在C++17中满足如下条件之一的对象被认为是 聚合体 :

然而,要想使用聚合体初始化来 初始化 聚合体,那么还需要满足如下额外的约束:

下一节就有一个因为不满足这些额外约束导致编译失败的例子。

C++17引入了一个新的类型特征is_aggregate<>

来测试一个类型是否是聚合体:

template<typename T>struct D : std::string, std::complex<T> {    std::string data;};D<float> s{{"hello"}, {4.5, 6.7}, "world"};         // 自从C++17起OKstd::cout << std::is_aggregate<decltype(s)>::value; // 输出1(true)

向后的不兼容性

注意下面的例子不能再通过编译:

struct Derived;struct Base {    friend struct Derived;private:    Base() {    }};struct Derived : Base {};int main(){    Derived d1{};   // 自从C++17起ERROR    Derived d2;     // 仍然OK(但可能不会初始化)}

在C++17之前,Derived不是聚合体。因此

Derived d1{};

会调用Derived隐式定义的默认构造函数,这个构造函数会调用基类Base的构造函数。

尽管基类的默认构造函数是private的,但在派生类的构造函数里调用它也是有效的,

因为派生类被声明为友元类。

自从C++17起,例子中的Derived是一个聚合体,所以它没有隐式的默认构造函数

(构造函数没有使用using声明继承)。因此,d1的初始化将是一个聚合体初始化,

如下表达式:

std::is_aggregate<Derived>::value

将返回true

然而,因为基类有一个private的构造函数(见上一节)所以不能使用花括号来初始化。

这和派生类是否是基类的友元无关。

“C++聚合体初始化的方法是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯