C++11 之前使用默认初始化
C++11
之前对非静态数据成员初始化需要用到初始化列表。
有个问题是,如果类的数据成员比较多,我们又需要定制一些数据成员的初始化操作的时候,需要写很多的构造函数。
来看一个例子:
#include <iostream>
#include <string>
class X {
public:
X() : a_(0), b_(0.), c_("hello world") {}
X(int a) : a_(a), b_(0.), c_("hello world") {}
X(double b) : a_(0), b_(b), c_("hello world") {}
X(const std::string c) : a_(0), b_(0.), c_(c) {}
void PrintX() {
std::cout << "----------------------" << std::endl;
std::cout << "a_: " << this->a_ << std::endl;
std::cout << "b_: " << this->b_ << std::endl;
std::cout << "c_: " << this->c_ << std::endl;
}
private:
int a_;
double b_;
std::string c_;
};
int main() {
X* x_1 = new X();
x_1->PrintX();
X* x_2 = new X(1);
x_2->PrintX();
X* x_3 = new X(2.0);
x_3->PrintX();
X* x_4 = new X("C++");
x_4->PrintX();
}
因为有时候要给不同的成员变量进行初始化,所以要写好几个不同版本的构造函数,并且可以发现构造函数里有很多冗余代码。
运行结果:
linrongjian@hhb-ssd:/data/modern_cpp$ g++ -std=c++11 nonstatic_datamemeber_init.cpp -o nonstatic_datamemeber_init
linrongjian@hhb-ssd:/data/modern_cpp$ ./nonstatic_datamemeber_init
----------------------
a_: 0
b_: 0
c_: hello world
----------------------
a_: 1
b_: 0
c_: hello world
----------------------
a_: 0
b_: 2
c_: hello world
----------------------
a_: 0
b_: 0
c_: C++
这种方式在数据成员变多的时候,需要频繁地更改和增加构造函数,维护起来非常的麻烦。
C++11 的默认初始化方式
C++11
允许在声明非静态数据成员的时候同时用 =
(声明时默认初始化) 和 {}
(列表初始化)。
还是刚才的例子,可以这样写:
#include <iostream>
#include <string>
class X {
public:
X() {}
X(int a) : a_(a) {}
X(double b) : b_(b) {}
X(const std::string c) : c_(c) {}
void PrintX() {
std::cout << "----------------------" << std::endl;
std::cout << "a_: " << this->a_ << std::endl;
std::cout << "b_: " << this->b_ << std::endl;
std::cout << "c_: " << this->c_ << std::endl;
}
private:
// 这里也可以用列表初始化 {}
int a_ = 0;
double b_ = 0.;
std::string c_ = "hello world";
};
int main() {
X* x_1 = new X();
x_1->PrintX();
X* x_2 = new X(1);
x_2->PrintX();
X* x_3 = new X(2.0);
x_3->PrintX();
X* x_4 = new X("C++");
x_4->PrintX();
}
可以发现在声明数据成员的时候直接用 =
初始化(也可以 {}
列表初始化)和构造函数的列表初始化同时使用了。
同时构造函数少了很多冗余代码,每个构造函数只需要专注于特殊成员的初始化(而不是写出全部数据成员的初始化),对于没写出来的数据成员,默认使用声明时初始化的值。
显然这种方式增强了代码可维护性。
运行效果和上面是等效的:
linrongjian@hhb-ssd:/data/modern_cpp$ g++ -std=c++11 nonstatic_datamemeber_init.cpp -o nonstatic_datamemeber_init
linrongjian@hhb-ssd:/data/modern_cpp$ ./nonstatic_datamemeber_init
----------------------
a_: 0
b_: 0
c_: hello world
----------------------
a_: 1
b_: 0
c_: hello world
----------------------
a_: 0
b_: 2
c_: hello world
----------------------
a_: 0
b_: 0
c_: C++
位域默认初始化(C++20)
有些变量在存储时不需要一个完整的字节,而只需要占用几个位。
为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几 个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。
C++20
允许对数据成员的位域进行默认初始化。
例:
#include <iostream>
class S {
public:
int x : 8 = 11;
int y : 4{7};
};
int main() {
S* s = new S();
std::cout << s->x << ' ' << s->y << std::endl;
}
这里低 8
位被初始化为 11
,高 4
位被初始化为 7
:
linrongjian@hhb-ssd:/data/modern_cpp$ g++ -std=c++2a bitfield_init.cpp -o bitfield_init
linrongjian@hhb-ssd:/data/modern_cpp$ ./bitfield_init
11 7