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

Возможно, это действительно простая вещь, но я новичок в 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 ]

23 голосов
/ 08 декабря 2010

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

extern int lettersArr[26];

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

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

int lettersArr[26] = { letA, /*...*/ };
4 голосов
/ 08 декабря 2010

Заголовок:

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));
2 голосов
/ 08 декабря 2010

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

extern int lettersArr[26];

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

1 голос
/ 09 декабря 2010

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

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

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

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

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

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

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

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

0 голосов
/ 20 сентября 2015

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

<code><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 */
0 голосов
/ 08 декабря 2010

попробуй:

lettersArr = { 1, 2, 3, 4 }
0 голосов
/ 08 декабря 2010

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

в заголовке

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 };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...