Подтвердить что ты не робот

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

Это, наверное, очень простая вещь, но я новичок в С++, поэтому мне нужна помощь.

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

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

но это не работает.

Я получил синтаксис неправильно или что-то еще? Каков правильный путь к этому?

Большое спасибо.

4b9b3361

Ответ 1

Добавьте extern в объявление в файле заголовка.

extern int lettersArr[26];

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

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

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

Ответ 2

Заголовок:

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

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

Ответ 4

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

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

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

  • используйте внутреннюю связь с помощью static или

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

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

Последние два решения - обходные пути для отсутствия данных "inline" в С++. То есть, возможность определять один и тот же объект области пространства имен в нескольких единицах перевода. У вас есть это для функций через 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;
}

Локальный статический в встроенной функции

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

Приветствия и hth.,

Ответ 5

Вы можете сделать это следующим образом:

в заголовке

extern int lettersArr[26];

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

Ответ 6

Здесь приведен фрагмент из одного из моих файлов заголовков (файл .cpp реализации реализует массив): (Для доступа к массиву используйте 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>

Ответ 7

попробовать:

lettersArr = { 1, 2, 3, 4 }