C++入門|C++の名前空間の使い方

同じpowerでも、流派が違えば別の力。名前空間を使えば、C++の大きなプログラムでも名前を安全に分けて管理できます。

C++では、名前空間を使うことで、同じ名前の変数や関数を別々の場所に分けて管理できます。

前に見たように、グローバル変数をそのまま使うと、プログラム全体で1つの変数を共有することになります。
そのため、ある関数で値を変更すると、別の関数から見たときにも値が変わってしまいます。

小さなプログラムなら問題になりにくいかもしれません。
しかし、大きなプログラムでは、複数の開発者が同じような名前の変数や関数を作ることがあります。

たとえば、ある開発者がpowerという名前で亀仙流の修行値を管理し、別の開発者が同じpowerという名前で惑星戦士流の戦闘値を管理したいとします。
この2つが同じ場所にあると、名前が衝突してしまいます。

そこで使うのが 名前空間 です。

ドラゴンボール風にたとえるなら、名前空間は流派ごとの修行場です。

亀仙流のpowerはTurtleSchoolの中に置く。
惑星戦士流のpowerはPlanetSchoolの中に置く。

このように場所を分けておけば、同じpowerという名前でも別々の値として扱えます。

学ぶ内容意味ドラゴンボール風のイメージ
namespace名前空間を定義する流派ごとの修行場を作る
using namespace指定した名前空間を使いやすくするその流派の技をその場で使いやすくする
::名前空間を明示して指定するどの流派の技かを指定する札
std::coutstd名前空間のcoutを使う標準流派の表示技を明示して使う
同名の変数名前空間が違えば共存できる同じpowerでも流派が違えば別物

名前空間を理解すると、C++でよく出てくる std::cout や using namespace std; の意味も分かりやすくなります。

名前空間を使うと同じ名前を分けられる

名前空間を使うと、同じ名前の変数を複数定義できます。

ただし、同じ名前空間の中に同じ名前を重複して定義することはできません。
名前空間が違うからこそ、同じ名前を安全に使えるのです。

たとえば、次のように考えると分かりやすいです。

名前空間変数名意味
TurtleSchoolpower亀仙流の修行値
PlanetSchoolpower惑星戦士流の戦闘値

どちらも変数名はpowerです。
しかし、所属している名前空間が違うため、別々の変数として扱えます。

C++では、このように名前の所属場所を分けることで、大きなプログラムでも名前の衝突を防ぎやすくなります。

図:名前空間を使うと同じpowerを分けられる

この図が示していること

この図では、TurtleSchoolとPlanetSchoolという2つの名前空間に、それぞれpowerという変数があることを表しています。

同じpowerという名前でも、TurtleSchool::powerとPlanetSchool::powerのように名前空間を付ければ、別々の変数として区別できます。

名前空間は、同じ名前がぶつからないようにするための仕切りのような役割を持っています。

名前空間を使ったプログラム

それでは、名前空間を使ったサンプルプログラムを見てみましょう。

ここでは、亀仙流の修行値と惑星戦士流の戦闘値を、それぞれpowerという名前で管理します。
同じpowerという名前ですが、名前空間が違うため、別々の変数として扱えます。

プロジェクト/ファイル名: Chap2_06/main.cpp

#include <iostream>

using namespace std;

// 亀仙流の名前空間
namespace TurtleSchool {
    int power;
}

// 惑星戦士流の名前空間
namespace PlanetSchool {
    int power;
}

// 関数のプロトタイプ宣言
void turtleTraining();
void planetTraining();

int main(int argc, char** argv) {
    // それぞれの名前空間にあるpowerへ値を代入する
    TurtleSchool::power = 20;
    PlanetSchool::power = 30;

    // main関数では名前空間を明示して表示する
    cout << "main:TurtleSchool::power=" << TurtleSchool::power << endl;
    cout << "main:PlanetSchool::power=" << PlanetSchool::power << endl;

    turtleTraining();
    planetTraining();

    return 0;
}

// 亀仙流の修行処理
void turtleTraining() {
    // この関数の中ではTurtleSchoolの名前を使いやすくする
    using namespace TurtleSchool;

    cout << "turtleTraining:TurtleSchool::power=" << power << endl;
    cout << "turtleTraining:PlanetSchool::power=" << PlanetSchool::power << endl;

    // TurtleSchoolのpowerの値を変更する
    power = 40;
}

// 惑星戦士流の修行処理
void planetTraining() {
    // この関数の中ではPlanetSchoolの名前を使いやすくする
    using namespace PlanetSchool;

    cout << "planetTraining:TurtleSchool::power=" << TurtleSchool::power << endl;
    cout << "planetTraining:PlanetSchool::power=" << power << endl;
}

実行すると、次のように表示されます。

main:TurtleSchool::power=20
main:PlanetSchool::power=30
turtleTraining:TurtleSchool::power=20
turtleTraining:PlanetSchool::power=30
planetTraining:TurtleSchool::power=40
planetTraining:PlanetSchool::power=30

この結果を見ると、TurtleSchool::powerとPlanetSchool::powerが別々に管理されていることが分かります。

main関数でTurtleSchool::powerに20、PlanetSchool::powerに30を代入しています。
そのあと、turtleTraining関数でTurtleSchool::powerを40に変更しています。

しかし、PlanetSchool::powerは30のままです。

変数最初の値変更後
TurtleSchool::power2040
PlanetSchool::power3030

つまり、同じpowerという名前でも、名前空間が違えば別の変数として扱えるということです。

名前空間の定義方法

名前空間は、namespaceを使って定義します。

基本の書き方は、次の形です。

namespace 名前空間名 {
    変数や関数の定義
}

今回のプログラムでは、次のように2つの名前空間を定義しています。

namespace TurtleSchool {
    int power;
}

namespace PlanetSchool {
    int power;
}

TurtleSchoolの中にはpowerがあります。
PlanetSchoolの中にもpowerがあります。

名前は同じpowerですが、所属している名前空間が違うため、別々の変数になります。

記述意味
namespace TurtleSchoolTurtleSchoolという名前空間を作る
namespace PlanetSchoolPlanetSchoolという名前空間を作る
int power;その名前空間の中にpowerを定義する

ドラゴンボール風にたとえるなら、namespace TurtleSchoolは亀仙流の道場を作る宣言です。
namespace PlanetSchoolは惑星戦士流の道場を作る宣言です。

それぞれの道場の中にpowerという修行値を置いているので、同じ名前でも混ざりません。

同じ名前空間の中では同じ名前は使えない

名前空間を使えば、違う名前空間に同じ名前を定義できます。

しかし、同じ名前空間の中に同じ名前を重複して定義することはできません。

たとえば、次のような考え方です。

namespace TurtleSchool {
    int power;
    int speed;
}

これは問題ありません。
powerとspeedは名前が違うからです。

しかし、同じTurtleSchoolの中でpowerを2回定義することはできません。

namespace TurtleSchool {
    int power;
    int power;
}

このような書き方は、同じ道場の中に同じ名前の修行値が2つある状態です。
C++としても、どちらのpowerを使えばよいのか分からなくなります。

状態使えるか
TurtleSchool::power と PlanetSchool::power使える
TurtleSchool内にpowerとspeed使える
TurtleSchool内にpowerを2つ使えない

名前空間は、名前を自由に重複させるための仕組みではありません。
名前の所属を分けることで、衝突を防ぐための仕組みです。

名前空間の変数を使う方法

名前空間の中にある変数を使う方法は、大きく分けて2つあります。

1つ目は、using namespaceを使う方法です。
2つ目は、名前空間名::変数名の形で明示する方法です。

方法書き方特徴
using namespaceを使うusing namespace TurtleSchool;その範囲内でpowerと短く書ける
::で明示するTurtleSchool::powerどの名前空間かはっきり分かる

どちらも大切な使い方です。

学習中は、まず名前空間名::変数名の形をしっかり理解しておくと安心です。
この形が分かると、std::coutやstd::endlの意味も自然に見えてきます。

using namespaceで名前空間を使いやすくする

turtleTraining関数では、次のように書いています。

using namespace TurtleSchool;

この宣言を書くと、この関数の中ではTurtleSchoolの中にある名前を短く使えるようになります。

そのため、次の行ではTurtleSchool::powerではなく、powerと書いています。

cout << "turtleTraining:TurtleSchool::power=" << power << endl;

このpowerは、TurtleSchool::powerを指しています。

記述意味
using namespace TurtleSchool;TurtleSchoolの名前を使いやすくする
powerTurtleSchool::powerとして扱われる
PlanetSchool::powerPlanetSchoolのpowerを明示して使う

ただし、using namespace TurtleSchool;を書いていても、PlanetSchool::powerのように明示すれば、別の名前空間のpowerにもアクセスできます。

ドラゴンボール風にたとえるなら、turtleTraining関数の中では、亀仙流の道場にいる状態です。
そのため、powerと書けば亀仙流のpowerを意味します。

ただし、惑星戦士流のpowerを見たい場合は、PlanetSchool::powerと流派名を明示します。

図:using namespaceを使うと短く書ける

この図が示していること

この図では、using namespace TurtleSchool;を書くと、その範囲内でpowerがTurtleSchool::powerとして扱われることを表しています。

ただし、別の名前空間にあるpowerを使いたい場合は、PlanetSchool::powerのように名前空間を明示します。

using namespaceは短く書けて便利ですが、どの名前空間の名前を使っているのかを理解しておくことが大切です。

::で名前空間を明示する

main関数では、次のように名前空間を明示しています。

TurtleSchool::power = 20;
PlanetSchool::power = 30;

この書き方では、どの名前空間のpowerなのかがはっきり分かります。

::は、スコープ解決演算子と呼ばれる記号です。
名前空間の中にある変数や関数を指定するときに使います。

書き方意味
TurtleSchool::powerTurtleSchool名前空間のpower
PlanetSchool::powerPlanetSchool名前空間のpower
std::coutstd名前空間のcout
std::endlstd名前空間のendl

ドラゴンボール風にたとえるなら、::は流派名と技名をつなぐ札です。

TurtleSchool::powerなら、亀仙流のpower。
PlanetSchool::powerなら、惑星戦士流のpower。
std::coutなら、C++標準流派のcoutです。

このように、::を使うと、どの名前空間に属する名前なのかを明確にできます。

using namespaceと::の使い分け

using namespaceを使うと、コードを短く書けます。
一方で、::を使うと、どの名前空間のものなのかが明確になります。

方法長所注意点
using namespace短く書ける名前の所属が見えにくくなることがある
名前空間名::名前所属が明確少し長くなる

今回のプログラムでは、turtleTraining関数とplanetTraining関数の中でusing namespaceを使っています。

using namespace TurtleSchool;
using namespace PlanetSchool;

一方、main関数では、TurtleSchool::powerとPlanetSchool::powerを使って、名前空間を明示しています。

cout << "main:TurtleSchool::power=" << TurtleSchool::power << endl;
cout << "main:PlanetSchool::power=" << PlanetSchool::power << endl;

どちらの方法も正しいです。
大切なのは、どのpowerを使っているのかを自分で説明できることです。

関数ごとの処理の流れ

今回のプログラムの流れを順番に見てみましょう。

まず、main関数で2つのpowerに値を代入します。

TurtleSchool::power = 20;
PlanetSchool::power = 30;

この時点では、値は次のようになっています。

変数
TurtleSchool::power20
PlanetSchool::power30

次に、turtleTraining関数を呼び出します。

turtleTraining();

turtleTraining関数の中では、using namespace TurtleSchool;があるため、powerと書くとTurtleSchool::powerを意味します。

using namespace TurtleSchool;
power = 40;

そのため、TurtleSchool::powerだけが40に変わります。

変数
TurtleSchool::power40
PlanetSchool::power30

次に、planetTraining関数を呼び出します。

planetTraining();

planetTraining関数の中では、using namespace PlanetSchool;があるため、powerと書くとPlanetSchool::powerを意味します。

using namespace PlanetSchool;

そのため、planetTraining関数内のpowerはPlanetSchool::powerです。
一方、TurtleSchool::powerを使うときは、名前空間を明示しています。

関数powerと書いた場合の意味
turtleTrainingTurtleSchool::power
planetTrainingPlanetSchool::power

このように、using namespaceを書いた場所によって、powerがどの名前空間を指すかが変わります。

名前空間を使うと値の干渉を防ぎやすい

名前空間を使わない場合、グローバル変数powerはプログラム全体で1つだけでした。
そのため、ある関数でpowerを変更すると、別の関数にも影響しました。

しかし、名前空間を使えば、同じpowerという名前でも別々に管理できます。

名前空間なし名前空間あり
powerが1つだけTurtleSchool::powerとPlanetSchool::powerを分けられる
どこかで変更すると全体に影響しやすい名前空間ごとに別の値として管理できる
大規模開発で衝突しやすい名前の衝突を避けやすい

ドラゴンボール風にいうと、名前空間なしでは、全流派が1つの共通戦闘力メーターを触っている状態です。
名前空間ありでは、亀仙流と惑星戦士流がそれぞれ専用の戦闘力メーターを持っている状態です。

そのため、亀仙流のpowerを変更しても、惑星戦士流のpowerには影響しません。

図:main関数では::で2つのpowerを明示する

この図が示していること

この図では、main関数からTurtleSchool::powerとPlanetSchool::powerを明示して使う流れを表しています。

TurtleSchool::powerと書けば、TurtleSchool名前空間のpowerを使います。
PlanetSchool::powerと書けば、PlanetSchool名前空間のpowerを使います。

::を使うことで、同じpowerという名前でも、どちらの名前空間にあるものなのかをはっきり指定できます。

std名前空間をusing namespaceなしで使う

C++では、coutやendlはstd名前空間の中にあります。

これまでのサンプルでは、次のように書いていました。

using namespace std;

この宣言を書くと、coutやendlを短く書けます。

しかし、using namespace std;を書かずに、std::coutやstd::endlと明示する方法もあります。

プロジェクト/ファイル名: Chap2_07/main.cpp

#include <iostream>

int main(int argc, char** argv) {
    // std名前空間のcoutとendlを明示して使う
    std::cout << "HelloWorld." << std::endl;

    // プログラムが正常に終わったことを示す
    return 0;
}

実行すると、次のように表示されます。

HelloWorld.

このプログラムでは、using namespace std;を使っていません。

その代わりに、coutの前にstd::を付けています。
endlにもstd::を付けています。

書き方意味
std::coutstd名前空間のcout
std::endlstd名前空間のendl

このように書けば、std名前空間を使うことを明示できます。

using namespace std;とstd::coutの違い

using namespace std;を使う書き方と、std::coutと書く方法は、どちらもstd名前空間の機能を使うための方法です。

書き方特徴
using namespace std; + cout短く書ける
std::cout名前空間が明確に分かる

学習用の短いプログラムでは、using namespace std;を使うとコードがすっきりします。
一方で、大きなプログラムでは、std::coutのように名前空間を明示したほうが、どこの名前なのか分かりやすいことがあります。

ドラゴンボール風にたとえるなら、using namespace std;は「この修行場では標準流派の技をそのまま使う」と宣言する方法です。
std::coutは「標準流派のcoutを使う」と毎回はっきり書く方法です。

どちらも正しい使い方ですが、名前空間の意味を理解したうえで選ぶことが大切です。

名前空間の使い方で押さえておきたいポイント

名前空間を使うときは、次のポイントを意識しましょう。

ポイント内容
namespaceで名前空間を定義する変数や関数の所属場所を作る
名前空間が違えば同じ名前を使えるTurtleSchool::powerとPlanetSchool::powerは別物
同じ名前空間内では同名を重複できない同じ道場に同じ名前の変数は置けない
using namespaceで短く書けるpowerと書くだけで使える場合がある
::で明示できるどの名前空間の名前かを指定できる
stdも名前空間coutやendlはstdの中にある
using namespace std;なしでも書けるstd::coutやstd::endlを使う

名前空間は、C++で名前の衝突を防ぐための大切な仕組みです。

小さなプログラムでは、少し大げさに感じるかもしれません。
しかし、プログラムが大きくなり、複数の機能や複数の開発者が関わるようになると、名前空間のありがたさが見えてきます。

ドラゴンボール風に言えば、名前空間は流派ごとに修行場を分けるための仕組みです。
同じpowerという名前でも、TurtleSchool::powerとPlanetSchool::powerのように分ければ、値が混ざらず安全に扱えます。

using namespaceを使えば短く書けます。
::を使えば所属をはっきり示せます。

この2つの使い方を理解しておくと、C++のコードに出てくるstd::coutやstd::endlも自然に読めるようになります。