是否可以在构造函数之外初始化
static const
数据成员?可以在声明数据成员的地方初始化吗?
class A {
private:
static const int a = 4;
/*...*/
};
是的,你可以,但仅限于 int 类型。 如果您希望静态成员是任何其他类型,则必须在 cpp 文件中的某个位置定义它。
class A{
private:
static const int a = 4; // valid
static const std::string t ; // can't be initialized here
...
...
};
// in a cpp file where the static variable will exist
const std::string A::t = "this way it works";
另请注意,此规则已在 C++11 中删除,现在(使用提供该功能的编译器)您可以直接在类成员声明中初始化您想要的内容。
类的成员列表中静态数据成员的声明不是定义。您必须在类声明之外、命名空间范围内定义静态成员。例如:
class X
{
public:
static int i;
};
int X::i = 0; // definition outside class declaration
一旦定义了静态数据成员,即使静态数据成员的类的对象不存在,它也存在。在上面的示例中,即使定义了静态数据成员 X::i,类 X 的对象也不存在。
命名空间范围内的类的静态数据成员具有外部链接。静态数据成员的初始值设定项位于声明该成员的类的范围内。
静态数据成员可以是除 void 或用 const 或 volatile 限定的 void 之外的任何类型。您不能将静态数据成员声明为可变的。
程序中只能有一个静态成员的定义。未命名类、未命名类中包含的类以及本地类不能有静态数据成员。
静态数据成员及其初始值设定项可以访问其类的其他静态私有和受保护成员。以下示例显示如何使用其他静态成员初始化静态成员,即使这些成员是私有的:
class C {
static int i;
static int j;
static int k;
static int l;
static int m;
static int n;
static int p;
static int q;
static int r;
static int s;
static int f() { return 0; }
int a;
public:
C() { a = 0; }
};
C c;
int C::i = C::f(); // initialize with static member function
int C::j = C::i; // initialize with another static data member
int C::k = c.f(); // initialize with member function from an object
int C::l = c.j; // initialize with data member from an object
int C::s = c.a; // initialize with nonstatic data member
int C::r = 1; // initialize with a constant value
class Y : private C {} y;
int C::m = Y::f();
int C::n = Y::r;
int C::p = y.r; // error
int C::q = y.f(); // error
C::p 和 C::q 的初始化会导致错误,因为 y 是从 C 私有派生的类的对象,并且 C 的成员无法访问其成员。
如果静态数据成员是const整型或const枚举类型,则可以在静态数据成员的声明中指定常量初始值设定项。该常量初始值设定项必须是整型常量表达式。请注意,常量初始值设定项不是定义。您仍然需要在封闭的命名空间中定义静态成员。以下示例演示了这一点:
#include <iostream>
using namespace std;
struct X {
static const int a = 76;
};
const int X::a;
int main() {
cout << X::a << endl;
}
静态数据成员 a 声明末尾的 tokens = 76 是常量初始值设定项。
为了完整起见,我添加了静态模板成员变量。
template<class T> struct X{
static T x;
};
template<class T> T X<T>::x = T();
int main(){
X<int> x;
}
您无法在构造函数中初始化静态成员。您可以在声明时内联初始化整型类型。其他静态成员必须定义(在
.cpp
)文件中:
// .h
class A{
private:
static const int a = 4;
static const foo bar;
...
...
};
// .cpp
const foo A::bar = ...;
现代C++
常量静态成员
如果整型或枚举类型的静态数据成员被声明为 const (而不是易失性),则可以使用初始化程序对其进行初始化,其中每个表达式都是常量表达式,就在类定义内部:
struct X
{
const static int n = 1;
const static int m{ 2 }; // (Since C++11)
const static int k;
};
const int X::k = 3;
--
如果 LiteralType 的静态数据成员声明为 constexpr,则必须使用初始化器对其进行初始化,其中每个表达式都是常量表达式,位于类定义内部:(C++11 起)
struct X
{
constexpr static int arr[] = { 1, 2, 3 }; // OK
constexpr static std::complex<double> n = {1,2}; // OK
constexpr static int k; // Error: constexpr static requires an initializer
};
--
如果 const 非内联 (C++17 起) 静态数据成员或 constexpr 静态数据成员 (C++11 起)(C++17 前) 是 odr-used,则命名空间范围内的定义为仍然需要,但它不能有初始化程序。
constexpr 静态数据成员是隐式内联的,不需要在命名空间范围内重新声明。这种没有初始化程序(以前是必需的)的重新声明仍然是允许的,但已被弃用。 (自 C++17 起)
struct X
{
static const int n = 1;
static constexpr int m = 4;
};
const int *p = &X::n, *q = &X::m; // X::n and X::m are odr-used
const int X::n; // … so a definition is necessary
constexpr int X::m; // … (except for X::m in C++17)
--