web-dev-qa-db-ja.com

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

しかし、これは機能しません。

構文が間違っているか何かがありますか?これへの正しい方法は何ですか?

どうもありがとう。

25
tree-hacker

externをヘッダーファイルの宣言に追加します。

extern int lettersArr[26];

(また、配列を変更する予定がない限り、constも追加することを検討してください。)

定義にはタイプが必要です。 int(またはconst int):

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

ヘッダ:

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

ヘッダーの内容を次のように変更します。

extern int lettersArr[26];

そのため、定義ではなく宣言になります。

2
Kos

他の人は、配列の初期化を実装ファイルに移動する方法を説明しました。これは質問に正確に答えているわけではありませんが、知っておくと便利な回避策です。

C++ヘッダーファイルで配列を宣言したい

ヘッダーファイルに初期化を含めるなど、ヘッダーファイルに配列をすべて含めたい場合は、次のことができます。

  • それを与える内部リンケージstaticを使用して、または

  • インライン関数でlocal staticを使用する(効果的に外部リンケージをサポートする)、または

  • 少しテンプレートトリックを使用します(外部リンケージもサポートします)。

最後の2つの解決策は、C++に「inline」データがないための回避策です。つまり、複数の変換単位で同じ名前空間スコープオブジェクトを定義する機能。関数に対してはinlineを介してそれがありますが、残念ながらオブジェクトに対してはそうではありません:何らかの回避策を講じなければ、リンカーは複数の定義について抗議するだけです。

内部連携

これは一般的に良い解決策ではありません。ヘッダーが含まれる各翻訳単位に1つの配列を作成します。ただし、比較的小さい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;
}

インライン関数のローカルスタティック

これはおそらく、他のソリューションのいずれかを選択するための最優先の理由がない場合に使用する、一般に「最良の」ソリューションです。良いことの1つは、動的な初期化を簡単に提供できることです。ここでは、配列に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;
}

乾杯

次の方法でできます:

ヘッダーに

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

ヘッダーファイルの1つからの抜粋を以下に示します(実装.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>
0
G O'Rilla