Объявить массив в заголовке C++ и определить его в файле cpp?

это, вероятно, очень простая вещь, но я новичок в 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 ответов


добавить extern к объявлению в заголовочном файле.

extern int lettersArr[26];

(кроме того, если вы не планируете изменять массив, подумайте также о добавлении const.)

определение должно иметь тип. Добавить int (или const int):

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

:

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

измените то, что у вас есть в заголовке на:

extern int lettersArr[26];

Так что это станет объявлением, а не определением.


другие описали, как инициализация массива может быть перемещена в файл реализации, который точно не отвечает на ваш вопрос, но является обходным путем, который полезно знать.

Я просто хочу объявить массив в моем заголовочном файле c++

если вы действительно хотите иметь массив все в файле заголовка, в том числе с инициализацией в файле заголовка, то вы можете

  • дать ему внутренняя перелинковка С помощью static или

  • использовать локальные статические в встроенной функции (которая поддерживает эффективно внешнюю связь), или

  • немного шаблон трюк (также поддерживает внешние связи).

последние два решения являются обходными путями из-за отсутствия "inline " данные на C++. То есть возможность определить тот же объект области пространства имен в более чем одна единица перевода. У вас есть это для функций, via inline, но, к сожалению, не для объектов: без использования некоторого обходного пути компоновщик будет просто протестовать против нескольких определений.

внутренняя перелинковка

это, как правило, не является хорошим решением. Он создает один массив в каждой единице перевода, где включен заголовок. Но это предпочтительнее для относительно небольших 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;
}

локальная статика в inline функция

это, наверное, вообще "лучшее" решение, чтобы использовать, когда нет никаких весомых причин для выбора одного из других решений. Одна хорошая вещь заключается в том, что легко обеспечить динамическую инициализацию. Здесь я просто предположил, что вы никогда не будете хранить 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, Одно Правило Определения, делает специальное исключение для шаблонов:

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

Cheers & hth.,


Вы можете сделать это так:

в заголовке

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

вот фрагмент из одного из моих заголовочные файлы (реализация .файл cpp доступы массива): (Для доступа к массиву используйте dummy::messages вне пространства имен dummy.)

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

попробуй:

lettersArr = { 1, 2, 3, 4 }