在C++头文件中声明数组,然后在cpp文件中定义?

40

这可能是一个非常简单的问题,但我对C ++还很陌生,所以需要帮助。

我只想在我的C ++头文件中声明一个数组,例如:

int lettersArr[26];

然后在cpp文件中定义一个函数,例如:

    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 };

但是这不起作用。

我的语法有问题还是其他什么问题?正确的方式是什么?

非常感谢。

7个回答

33

在头文件的声明中添加 extern

extern int lettersArr[26];

另外,除非您计划更改数组,否则还应考虑添加const

定义必须具有类型。添加int(或const int):

int lettersArr[26] = { letA, /*...*/ };

1
当我使用它时,在hpp文件中出现了“为'lettersArr'指定的存储类”的错误。你知道为什么吗?谢谢。 - tree-hacker
@tree-hacker:那个声明是在一个类中还是其他什么地方? - aschepler
是的,它应该在头文件的类中,就像这样:class Letters {private: /* 声明 */ ...}。它应该放在哪里? - tree-hacker
6
这改变了很多!请在开头说出来。如果它是在类定义内部,那么它是类描述的一部分,而不是一个外部全局变量的声明,这是完全无关的概念!如果它是类的一部分,则将其添加到类定义中而无需使用“extern”,然后在构造函数中初始化它。 - Kos
如果你想让每个 Letters 对象都有自己的变量 lettersArr,那么把它放回原来的位置,并修复 Letters 类构造函数以初始化数组。如果你想让所有 Letters 对象共享一个单独的 lettersArr 数组,则将其设置为 static 成员。 - aschepler
显示剩余2条评论

4

标题:

extern int lettersArr[];

全局作用域中的源代码:

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 lettersArr[26];

函数中的源码:

int localLettersArr[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 };

memcpy (lettersArr, localLettersArr, sizeof (localLettersArr));

3

将头部中的内容更改为:

extern int lettersArr[26];

这样它就成为了声明而不是定义。


1
当我使用那个时,在hpp文件中出现了“为'lettersArr'指定的存储类”的错误。你知道为什么吗?谢谢。 - tree-hacker
编译通过了吗?你只收到这个错误吗?你用的是哪个编译器? - Kos

3
其他人已经描述了如何将数组初始化移到实现文件中,这并不完全回答了你的问题,但是这是一个有用的解决方法。如果你真的想要在头文件中声明数组,包括在头文件中进行初始化,那么你可以采取以下方法:给它使用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 )
    {
        // Assuming normal ASCII-based character set with contiguous alpha.
        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;
}

干杯并祝一切顺利。

1
这是我其中一个头文件的片段(实现.cpp文件访问该数组): (在dummy命名空间之外使用dummy::messages来访问该数组。)
<pre>
    namespace dummy {

const static string messages[] = {
        "Unix does not echo the password field. Why do you think this is?",
        "The firewall blocks external access to ouranos. You need to login to helios and ssh or sftp to ouranos",
        "You need to experience of the command line. Not all systems have a gui.",
};

class Message {
public:
    Message();
    virtual ~Message();

    string getMessage();
    string getMessage( int index );
    int getRandomNumber();
};

} /* namespace dummy */
</pre>

0
你可以这样做:
在头文件中。
extern int lettersArr[26];

in .cpp

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 };

当我使用'lettersArr'时,hpp文件中出现了"为'lettersArr'指定了存储类"的错误。您知道原因吗?谢谢。 - tree-hacker

-2

尝试:

lettersArr = { 1, 2, 3, 4 }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接