C++在类的声明中初始化成员变量
在C++中,从C++11标准开始,可以在类的声明中直接初始化成员变量。这种语法被称为成员变量的默认初始化。这使得代码更清晰、更简洁,并且减少了构造函数中的初始化代码。
#include <iostream>
class MyClass
{
public:
int x = 10; // 声明中初始化
double y = 1.5; // 声明中初始化
MyClass() = default;
};
int main()
{
MyCalss obj;
std::cout << obj.x << ' ' << obj.y << '\n';
return 0;
}
默认初始化在很多场景下都可以用到,对于类中的基本类型变量,如果既未在类声明中初始化,又没在构造函数中进行初始化,它的值将是未定义的,后续会导致未定义行为,而频繁的在多个构造函数中对齐进行同样的初始化又略显冗杂。于是我们可以考虑在类的声明中对其进行初始化。
1. 初始化的顺序
我们知道,在C++11后,三种初始化方法(声明中初始化、列表初始化、构造函数初始化)都可以使用且不会冲突,所以我们也需要注意初始化的顺序:
声明中初始化->初始化列表->构造函数初始化
在下面的代码中,x、y在声明中的初始化首先被列表初始化覆盖,最终x在构造函数中的初始化又将列表初始化覆盖,最终x、y的值分别为20、5.5.
#include <iostream>
class MyClass
{
public:
int x = 10; // 声明中初始化
double y = 1.5; // 声明中初始化
MyClass() : x(5), y(5.5) // 列表初始化
{
x = 20; // 构造函数初始化
}
};
int main()
{
MyCalss obj;
std::cout << obj.x << ' ' << obj.y << '\n';
return 0;
}
2. 静态成员变量
一般的静态成员变量不能在类内直接初始化,必须在类外进行初始化:
#include <iostream>
class MyClass
{
public:
static int count;
MyClass() = default;
};
int MyClass::count = 10;
int main()
{
MyCalss obj;
std::cout << obj.count << '\n';
return 0;
}
但如果成员变量可以在编译时计算其值,那么可以使用 constexpr 进行初始化(C++11引入):
#include <iostream>
class MyClass
{
public:
static constexpr int count = 10; // constexpr 静态成员变量在类声明中初始化
MyClass() = default;
};
int main()
{
MyCalss obj;
std::cout << obj.count << '\n';
return 0;
}
注意事项
- 编译时常量:constexpr 静态成员变量必须是编译时常量,且其值必须是常量表达式。
- 内联初始化:在类内初始化 constexpr 静态成员变量时,实际上是在进行内联初始化。因此,这些变量在所有使用它们的翻译单元中都可用。
- 类型限制:constexpr 静态成员变量可以是整数、浮点数等基本类型,也可以是支持编译时常量表达式的用户定义类型。
3. 常量成员变量、引用成员变量
常量成员变量(const)和引用成员变量(&)必须在构造函数初始化列表中初始化,因为它们需要在对象创建时就被赋值。
#include <iostream>
class MyClass
{
public:
const int x;
double &ref;
MyClass(int a, int &b) : x(a), ref(b) {} // 列表初始化
};
int main()
{
MyCalss obj;
std::cout << obj.x << ' ' << obj.ref << '\n';
return 0;
}
关于列表初始化的诸多细节在此不做详谈,在之后的文章中会进行介绍。