网站首页 > 博客文章 正文
支持位段类型的类成员的直接初始化
C++ 20 增加了支持位段类型的类成员的初始化,例如下面的代码:
#include <iostream>
class CA
{
public:
int m_a1 { 2 }; // (1)C++11开始支持,大括号方式的普通变量初始化
int m_a2 = 4; // (2)C++11开始支持,等号方式的普通变量初始化
int m_b1 : 5 { 6 }; // (3)C++20开始支持,大括号方式的位段变量初始化
int m_b2 : 11 = 8; // (4)C++20开始支持,等号方式的位段变量初始化
};
int main( int argc, char * argv[] )
{
CA a1;
std::cout << a1.m_a1 << " " << a1.m_a2 << std::endl;
std::cout << a1.m_b1 << " " << a1.m_b2 << std::endl;
return 0;
}
使用GCC编译时,指定不同的C++标准时,编译的结果也不一样:
[foo@test code]$ g++ -std=c++98 a2.cpp
a2.cpp:6:15: warning: non-static data member initializers only available with ‘-std=c++11’ or ‘-std=gnu++11’
6 | int m_a1 { 2 };
| ^
a2.cpp:7:13: warning: non-static data member initializers only available with ‘-std=c++11’ or ‘-std=gnu++11’
7 | int m_a2 = 4;
| ^
a2.cpp:8:13: error: expected ‘;’ at end of member declaration
8 | int m_b1 : 5 { 6 };
| ^
| ;
a2.cpp:8:15: error: expected unqualified-id before ‘{’ token
8 | int m_b1 : 5 { 6 };
| ^
a2.cpp:9:18: error: an assignment cannot appear in a constant-expression
9 | int m_b2 : 11 = 8;
| ^
a2.cpp:6:11: warning: extended initializer lists only available with ‘-std=c++11’ or ‘-std=gnu++11’
6 | int m_a1 { 2 };
| ^
a2.cpp:6:15: warning: extended initializer lists only available with ‘-std=c++11’ or ‘-std=gnu++11’
6 | int m_a1 { 2 };
| ^
[foo@test code]$ g++ -std=c++11 a2.cpp
a2.cpp:8:15: warning: default member initializers for bit-fields only available with ‘-std=c++2a’ or ‘-std=gnu++2a’
8 | int m_b1 : 5 { 6 };
| ^
a2.cpp:9:16: warning: default member initializers for bit-fields only available with ‘-std=c++2a’ or ‘-std=gnu++2a’
9 | int m_b2 : 11 = 8;
| ^
[foo@test code]$ ./a.out
2 4
6 8
[foo@test code]$ g++ -std=c++20 a2.cpp
[foo@test code]$ ./a.out
2 4
6 8
类成员变量初始化的延伸分析
在定义类的局部变量或者使用 new 动态创建类实例时,会调用类的构造函数,如果没有显式定义类的构造函数,会使用类的默认构造函数。在类的默认构造函数中,对于简单类型的成员变量,默认是不会初始化的,也就是它的值是不确定的,这种不确定性是潜在问题的根源。因此对这种简单类型的类成员进行显式初始化是一个良好的编程习惯。
早期的 C++ 需要单独编写构造函数来进行类成员的初始化,例如:
class CA2
{
public:
CA2() : m_c1( 2 ), m_c2( 4 ) { } // (1)使用构造函数进行初始化
int m_c1;
int m_c2;
};
这样的写法虽然直观,但有点冗长,因此在 C++ 11 标准里面,模仿局部变量初始化的方式,增加了类成员变量的直接初始化,支持使用大括号和等号的方式初始化:
class CA3
{
public:
int m_c1 { 3 };
int m_c2 = 6;
};
其实局部变量也可以使用圆括号进行初始化,但是圆括号进行初始化时,如果使用另一个变量进行初始化,变量又跟类型重名 ,就和定义一个函数雷同,产生二义性。因此局部变量不推荐使用圆括号来初始化,C++11 扩展支持类成员初始化时,就干脆不支持圆括号进行初始化了。
在这样的直接初始化基础上,还可以再定义CA3类的构造函数,如果构造函数中有成员变量的初始化,则以构造函数为准,如果未显式初始化,则沿用定义成员变量时的初始化,这样不同的构造函数可以有选择的只初始化部分成员变量,不需要每个构造函数都重复将所有成员变量都初始化。
C++ 11 中只支持普通类型的直接初始化,不支持位段的直接初始化,直到C++ 20 才支持
主要是因为定义位段的大小,和后面的等号初始化,容易产生二义性,所以需要较多的讨论,最后明确要求等号用于初始化,而不会跟前面的位段大小组成表达式。例如:
static int g1 = 3;
static const int g2 = 4;
class CA4
{
public:
int m_c1 : (g1 = 6); // (1)Error,赋值本身语法正确,但不是常量,而定义位段大小必须使用常量
int m_c2 : (g2 = 6); // (2)Error,常量不能赋值
int m_c3 : g2 = 6; // (3)OK,位段大小g2是常量,最后的 = 6 表示初始化,不会当(2)来解析
int m_c4 : true ? g2 : (g1 = 3); // (4)OK,g1赋值语法上正确,虽然不是常量,但实际并不会用到,也不会执行
int m_c5 : true ? g2 : g1 = 3; // (5)OK,最后的 = 3 表示初始化,不会当(4)来解析
};
从上面例子可以看到,位段大小如果使用 “ ? : ” 运算符,和等号初始化,会产生二义性,现在标准强制要求必须按初始化来解析。不过实际位段一般都是直接的数值常量,不会使用很复杂的表达式的。
- 上一篇: C++ 20新特性之模块
- 下一篇: C++20尝鲜:新增语法糖
猜你喜欢
- 2025-08-03 C++语法进阶-字符:字符变量(char)
- 2025-08-03 c++26新功能—Read-Copy-Update
- 2025-08-03 为什么Linux之父那么讨厌C++ 他骂的这几点。句句扎心
- 2025-08-03 为什么Linux之父那么讨厌C++ 他骂的这几点!句句扎心
- 2025-08-03 20道qiao牛逼的c++/c面试题
- 2025-08-03 C++学习教程_C++语言随到随学_不耽误上班_0基础
- 2025-08-03 20天轻松入门《C++第四章——函数》——4经坛教育
- 2025-08-03 看完侯捷老师所有C++视频之后的总结
- 2025-08-03 C++11+ 泛型编程(模板)
- 2025-08-03 C++20并发库新成员jthread(续)
你 发表评论:
欢迎- 08-06nginx 反向代理
- 08-06跨表插入连续的日期,sheetsname函数#excel技巧
- 08-06初中生也能学的编程,不走弯路,先用后学
- 08-06find命令的“七种武器”:远不止-name和-type
- 08-06恶意代码常见的编程方式
- 08-06kali2021ping 外网不通
- 08-06因为一个函数strtok踩坑,我被老工程师无情嘲笑了
- 08-06hadoop集群搭建详细方法
- 22℃nginx 反向代理
- 最近发表
- 标签列表
-
- ifneq (61)
- 字符串长度在线 (61)
- googlecloud (64)
- powershellfor (73)
- messagesource (71)
- plsql64位 (73)
- vueproxytable (64)
- npminstallsave (63)
- #NAME? (61)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- nacos启动失败 (64)
- ssh-add (70)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- qcombobox样式表 (68)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)