コンストラクターに少し問題があります。私のヘッダーファイルでは、次のように宣言します。
char short_name_[2];
私のコンストラクタでは:
Territory(std::string name, char short_name[2], Player* owner, char units);
void setShortName(char* short_name);
inline const char (&getShortName() const)[2] { return short_name_; }
私のcppファイル:
Territory::Territory(std::string name, char short_name[2], Player* owner,
char units) : name_(name), short_name_(short_name),
owner_(owner), units_(units)
{ }
私のエラー:
Territory.cpp:コンストラクター 'Territory :: Territory(std :: string、char *、Player *、char)':Territory.cpp:15:33:エラー: 'char *'から 'char [への割り当てで互換性のない型2] '
私はすでにそれを理解しましたchar[2] <=> char*
ですが、コンストラクターとget/setterについてこれを処理する方法がわかりません。
C++のraw配列は煩わしく、危険に満ちています。これが、特に理由がない限り、std::vector
またはstd::array
を使用する必要がある理由です。
まず、他の人が言ったように、char[2]
はchar*
と同じではないか、少なくとも通常は異なります。 char[2]
はchar
のサイズ2の配列で、char*
はchar
へのポインターです。配列は必要なときにいつでも最初の要素へのポインタに減衰するため、混乱することがよくあります。したがって、これは機能します:
char foo[2];
char* bar = foo;
しかし、その逆ではありません。
const char* bar = "hello";
const char foo[6] = bar; // ERROR
混乱に加えて、関数パラメーターを宣言する場合、char[]
はchar*
と同等です。したがって、コンストラクタでは、パラメータchar short_name[2]
は実際にはchar* short_name
です。
配列のもう1つの奇妙な点は、他の型のようにコピーできないことです(これは、関数パラメーターの配列がポインターとして扱われる理由の1つの説明です)。したがって、たとえば、私はできないこのようなことをすることができます:
char foo[2] = {'a', 'b'};
char bar[2] = foo;
代わりに、foo
の要素を反復処理してbar
にコピーするか、または std::copy
などの機能を使用する必要があります。
char foo[2] = {'a', 'b'};
char bar[2];
// std::begin and std::end are only available in C++11
std::copy(std::begin(foo), std::end(foo), std::begin(bar));
したがって、コンストラクタでshort_name
の要素をshort_name_
に手動でコピーする必要があります。
Territory::Territory(std::string name, char* short_name, Player* owner,
char units) : name_(name), owner_(owner), units_(units)
{
// Note that std::begin and std::end can *not* be used on pointers.
std::copy(short_name, short_name + 2, std::begin(short_name));
}
ご覧のとおり、これは非常に煩わしいので、十分な理由がない限り、生の配列(またはこの場合はstd::vector
)の代わりにstd::string
を使用する必要があります。
関数が引数として配列を必要とする場合、代わりに配列の最初の要素へのポインターを取得します。このポインターは配列ではなくポインターであるため、配列の初期化には使用できません。
引数として配列にreferencesを受け入れる関数を記述できます。
void i_dont_accept_pointers(const char (array&)[2]) {}
ここでの問題は、この配列参照を使用して別の配列を初期化できないことです。
class Foo {
char vars[2];
Foo(const char (args&)[2])
: vars(args) // This will not work
{}
};
C++ 11ではstd::array
が導入され、配列のこの問題やその他の問題が解消されました。古いバージョンでは、配列要素を反復処理して個別にコピーするか、std::copy
を使用する必要があります。
C++は、Cのほとんどの規則を保持しています。
Cの場合は、配列を渡すために常にchar *を使用します。これは、Cが配列を参照するためです。関数に渡された場合でも、sizeof (short_name_)
は8または4になります。これで、変数short_name_
に2バイトのスペースができました。
コンストラクタがshort_name_
に2バイトのメモリを割り当てました。そのバイトをそれにコピーするか、char *ポインタを使用して、サイズが2であると想定する必要があります。
第9章の「エキスパートCプログラミング:ディープCシークレット」を読んで理解してください。
簡単にするために、これはCスタイルのコードにすることができます。
#include <stdio.h>
#include <iostream>
using namespace std;
class Territory {
private:
string s;
char c[2];
public:
Territory(std::string a, char b[2] /*visualize as char *b*/) {
s = a;
c[0] = b[0]; //or use strcpy
c[1] = b[1];
}
void PrintMe() {
printf ("As string %s as char %c or %s\n",this->s.c_str(), c[0],c);
}
};
main () {
Territory a("hello", "h");
a.PrintMe();
}