其他人已经描述了如何将数组初始化移到实现文件中,这并不完全回答了你的问题,但是这是一个有用的解决方法。如果你真的想要在头文件中声明数组,包括在头文件中进行初始化,那么你可以采取以下方法:给它使用static关键字来赋予内部链接性,或者在内联函数中使用局部静态变量(支持有效的外部链接性),或者使用一些小的模板技巧(也支持外部链接性)。后面两种方法是C++中缺少"内联数据"的解决方法。也就是说,能够通过inline定义相同的命名空间作用域对象在多个翻译单元中。对于函数,你可以通过inline实现这一点,但不幸的是对于对象来说没有这样的机制:如果不采取一些解决方法,连接器将抗议多重定义。这些方法都是对缺少内联数据的C++的解决方法。通常情况下,内部链接性并不是一个好的解决方案。因为它会在包含头文件的每个翻译单元中创建一个数组。但是对于比较小的const对象来说,这是一个较为简单的方案。
#include <stddef.h>
#include <iostream>
int const letA = 'A';
int const letB = 'B';
int const letC = 'C';
int const letD = 'D';
int const letE = 'E';
int const letF = 'F';
int const letG = 'G';
int const letH = 'H';
int const letI = 'I';
int const letJ = 'J';
int const letK = 'K';
int const letL = 'L';
int const letM = 'M';
int const letN = 'N';
int const letO = 'O';
int const letP = 'P';
int const letQ = 'Q';
int const letR = 'R';
int const letS = 'S';
int const letT = 'T';
int const letU = 'U';
int const letV = 'V';
int const letW = 'W';
int const letX = 'X';
int const letY = 'Y';
int const letZ = 'Z';
static int lettersArr[26] =
{
letA, letB, letC, letD, letE, letF, letG, letH,
letI, letJ, letK, letL, letM, letN, letO, letP, letQ, letR, letS,
letT, letU, letV, letW, letX, letY, letZ
};
int main()
{
using namespace std;
for( int i = 0; i < 26; ++i )
{
cout << char( lettersArr[i] );
}
cout << endl;
}
内联函数中的本地静态变量
当没有选择其他解决方案时,这可能是通常“最好”的解决方案。一个好处是很容易提供动态初始化。这里我假设你永远不会将0存储在数组中(如果这个假设不成立,请添加一些额外的检查逻辑):
#include <stddef.h>
#include <iostream>
template< class Type, int n >
int countOf( Type (&)[n] ) { return n; }
typedef int LettersArray[26];
inline LettersArray& lettersArrayRef()
{
static LettersArray theArray;
if( theArray[0] == 0 )
{
for( int i = 0; i < countOf( theArray ); ++i )
{
theArray[i] = i + 'A';
}
}
return theArray;
}
static LettersArray& lettersArr = lettersArrayRef();
int main()
{
using namespace std;
for( int i = 0; i < 26; ++i )
{
cout << char( lettersArr[i] );
}
cout << endl;
}
模板技巧
模板技巧之所以有效,是因为标准中的ODR(One Definition Rule)对模板有特殊的豁免规定:
#include <stddef.h>
#include <iostream>
int const letA = 'A';
int const letB = 'B';
int const letC = 'C';
int const letD = 'D';
int const letE = 'E';
int const letF = 'F';
int const letG = 'G';
int const letH = 'H';
int const letI = 'I';
int const letJ = 'J';
int const letK = 'K';
int const letL = 'L';
int const letM = 'M';
int const letN = 'N';
int const letO = 'O';
int const letP = 'P';
int const letQ = 'Q';
int const letR = 'R';
int const letS = 'S';
int const letT = 'T';
int const letU = 'U';
int const letV = 'V';
int const letW = 'W';
int const letX = 'X';
int const letY = 'Y';
int const letZ = 'Z';
template< class Dummy >
struct Letters_
{
static int array[26];
};
template< class Dummy >
int Letters_< Dummy >::array[26] =
{
letA, letB, letC, letD, letE, letF, letG, letH,
letI, letJ, letK, letL, letM, letN, letO, letP, letQ, letR, letS,
letT, letU, letV, letW, letX, letY, letZ
};
static int (&lettersArr)[26] = Letters_<void>::array;
int main()
{
using namespace std;
for( int i = 0; i < 26; ++i )
{
cout << char( lettersArr[i] );
}
cout << endl;
}
干杯并祝一切顺利。
Letters
对象都有自己的变量lettersArr
,那么把它放回原来的位置,并修复Letters
类构造函数以初始化数组。如果你想让所有Letters
对象共享一个单独的lettersArr
数组,则将其设置为static
成员。 - aschepler