C++では、本来「変数」とはいわず「オブジェクト」といいます。これは、いわゆるオブジェクト指向におけるオブジェクトではなく、メモリ上に配置される変数や定数をひっくるめたものと考えてかまいません。「変数」という呼び方もないわけではありませんが、どちらかというと変数として扱うオブジェクトのことを指すようです。厳密な定義はともかく、ここでは分かりやすいように「変数」と呼ぶことにします。
変数の宣言
C++のプログラムで変数を使うには、最初に宣言が必要になります。変数の宣言は、若干の例外はありますが、おおむね次のように書きます。
0 1 2 |
型名 変数名; |
型名というのは、その変数がどんな性質を持つかを表すものです。例えば、変数が整数を表すものだとか、文字列を表すものだとかいうことを指定します。変数名には、分かりやすいように自分で好きな名前を付けることができますが、使用できる文字に制約があります。変数名は、必ずアルファベットで始め、2文字目以降は、アルファベット、数字、または下線(アンダースコア、アンダーバー) ‘_’ を使うことができます。
正確には、国際文字名といって、UTF-16やUTF-32の値を直接指定することも、漢字などの多バイト文字も使うこともできるのですが、ここでは詳しく触れないことにします。
また、1文字目が下線の名前(実際にはもっと複雑なルールですが、こう覚えておけば間違いありません)はコンパイラや標準ライブラリに予約されているため、使用することができません。変数名に連続した下線が含まれる名前も同様に予約されているため、使用できません。
では、具体的なサンプルを以下に示します。
0 1 2 3 4 |
int i; // 整数型の変数 double x; // 浮動小数点型の変数 std::string s; // 文字列型の変数 |
実際にはもっと多くの型を利用することができますし、新しい型を自分で定義することもできます。なお、上のサンプルで挙げたstd::stringを使う場合は、あらかじめ#include <string>を記述しておく必要があります。このように、型の中には、あらかじめ何らかのヘッダをインクルードする必要があるものもあります。
初期値を設定する
変数は原則として、単に宣言しただけではその値は不定になります。そのため、普通は適切な初期値を設定する必要があります。初期値を設定するには次のようにします。
0 1 2 3 4 |
int i = 123; double x = 1.23; std::string s = "abc"; |
このように、等号を使えば変数の初期値を設定することができます。なお、初期値の設定は次のように括弧を用いて行うこともできます。
0 1 2 3 4 |
int i(123); double x(1.23); std::string s("abc"); |
ところで、変数の型がstd::stringの場合、初期値を設定しなければ””で初期化したのと同じになります。このように、中には暗黙的に初期値が設定される型もあります。より詳しく知りたい方は、クラスのデフォルトコンストラクタについて調べてみてください。
変数を宣言できる場所
C++では、変数の宣言は、大きく分けて二箇所で行うことができます。ひとつは関数の中であり、もうひとつは関数の外です。関数の中で宣言した変数(オブジェクト)を「局所オブジェクト」といい、関数の外で宣言した変数(オブジェクト)を「非局所オブジェクト」といいます。
0 1 2 3 4 5 6 7 |
int non_local = 123; // 非局所オブジェクト int main() { int local = 456; // 局所オブジェクト ... } |
また、関数の中では、式の途中のような中途半端な場所でない限り、ほとんどの場所で変数を宣言することができます。例えば、
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
int main() { int a; // 関数の先頭 int b; // 関数の途中 for (int c = 0; c < 10; c++) // forの初期文として { ... } if (int d = foo()) // 条件として { ... } } |
といった具合です。条件として行う変数の宣言は、if文に限らず、for文、while文、switch文でも可能です。ただし、この文脈で配列の宣言を行うことはできませんし、変数の値を暗黙的にbool型に変換できる必要もあります。
変数の有効範囲と生存期間
変数の有効範囲(スコープ)というのは、その変数をその名前で参照することができる範囲のことです。関数の外で宣言した変数は、その宣言を行った位置からソースファイルの最後まで有効です。関数の中で宣言した変数は、その変数を宣言した波括弧 { } で囲まれたブロックの最後まで有効です。for文の初期文やif文などの条件として宣言した変数は、その宣言を行った文(for文とかif文とか)の中だけで有効です。
0 1 2 3 |
if (expr) int a = func(); |
におけるaのように、if文、for文、while文、do文switch文の副文そのものとして宣言された変数も、その副文の中だけで有効となります。
有効範囲によく似た概念に生存期間があります。生存期間というのは、簡単に言えばその変数の寿命のことです。有効範囲が空間的に参照可能な範囲を表しているのに対して、生存期間は時間的に参照可能な範囲を表していると考えてください。関数の外で宣言した変数の生存期間はプログラムの終了までです。ただし、プログラムの終了時には、後に宣言したものから順に生存期間を終えていきます。関数の中で宣言した変数は、プログラムの実行位置が、その変数の有効範囲から抜けるときに生存期間を終えます。
関数の中で宣言した変数でも、場合によっては、有効範囲を抜けた後まで生存期間を引き延ばしたい場合があります。例えば、
0 1 2 3 4 5 6 |
unsigned int count() { unsigned int value = 0; return value++; } |
count関数は、呼び出すたびに1ずつ大きな値を返したいのですが、上のように書いてしまうと常に0を返すことになります。count関数から抜けるたびにvalueの生存期間が終わってしまうためです。これを解決するには、
0 1 2 3 4 5 6 |
unsigned int count() { static unsigned int value = 0; return value++; } |
のように、static指定子を付けて宣言する必要があります。static指定子は「記憶クラス指定子」の一種で、これを付けた変数は、関数の外で宣言した変数と同様、プログラムの終了時まで生存期間を持つことになります。
モダンC++について
長い間、C++における変数の扱いはこれまでに説明した内容を把握すればよかったのですが、2011年版の標準規格であるC++11以降は事情が変わってきています。書き方が変わったというより、より便利な機能が追加されたと考えればいいでしょう。
話が長くなりすぎますので、今回はここまでにしておいて、C++11以降の話はまた別の機会にあらためて行うことにします。