単に宣言された領域
名前空間はシンボルのスコープ( 見える範囲 )を決定する。
名前空間は異なる file をまたがっていても良い
使いどころは
名前( 識別子, Symbol )を局所化すること
配置する領域を指定して衝突しないようにする
■ 名前空間にあるシンボルを指定する
名前空間の中になるシンボルを指定するには スコープ演算子 :: をつかう。
std::vector< int > a;
std::cout
MyLibrary::Test t;
名前空間はネストできるので、指定する場合もルートからたどる。
MyLibrary::Math::Vector v;
毎回長い名前を指定するのも手間なので using namespace でシンボルの検索する場所を指定する。
using namespace MyLibrary::Math;
Vector v;
using namespace std;
vector< int > a;
■ 名前空間の使いどころ
同じクラス名をつけたいが、他のライブラリ内の名前と重複しないようにしたいときに使う。
たとえば Manager という管理クラスを複数人で別モジュールごとにつくる場合に
他を気にせずに同名の名前をつかうことができる。
各モジュールをつくる側は自分の名前空間でのみ考えることができる。
ある部署で部長というと、その部署の部長を指すのと同じ。
namespace Sound {
class Manager {
};
}
namespace IO {
class Manager {
};
class Mouse {
// これは自分の今いる名前空間 IO の Manager を指すので局所的に名前を指定できる。
Manager m;
};
}
名前空間を使わない場合は長い名前をつけることになる
class IO_Manager {
};
class Sound_Manager {
};
逆にモジュールの利用者は注意が必要。
どちらの Manager か明示する必要がある。
Sound::Manager snd_manager;
IO::Manager io_manager;
■ 名前の検索する順番
POINT
名前空間が入れ子になった場合は次の順番で名前が検索される。
基本ルール
自分のいる名前空間から最初に検索する。
例外ルール
継承している基底クラスがあれば、その名前空間を優先する
class Child;
class Title : public Base::Child {
// 継承をしているクラスの名前が優先されるので, Child は Base::Child になる。
Child *c;
};
// 明示するには
::Child *c;
}
■ よく使う名前はネームスペースにいれる
Vector, Node といった名前(シンボル)はいかにもよく使われるのでネームスペースにいれてやる。
かぶりそうな名前を, NameSpace でくるんでやる。
namespace MyLib{
class Vector {
};
int func() {
// MyLib::Vector クラスのこと
Vector v;
}
}
POINT
主語::symbol として考えるとわかりやすい
犬::jump();
string 犬::name; // 犬の名前
新しい標準関数はstd名前空間におかれる
namespace tokyo
{
// tokyo の suzuki さん
char *suzuki;
void foo(void){
// some code ...
}
// namespace 内では , block{} と同じく
// namespace 内から検索される
{
// tokyo::suzuki が参照される
printf( "name %s" , suzuki );
// 外の suzuki を見たいなら :: と明示する
printf( "name %s" , ::suzuki );
}
}
指定した namespace を見えるようにする
using namespace tokyo; // これ以降は暗黙でtokyoを調べてくれる
{ おとなりの } さとうさん.
-> でも毎度指定するのはメンドイ.
-> なので, どこどこさんちの話ね.( using namespace おとなりの) と言おう
こうするのもありかも ?
// これは実装の方法 !. 使うときはどうだろう ?
namespace 3年 {
namespace B組 {
void Teacher::teach() {
///
cout < < "人という字は..." < < endl;
}
}
}
// Namespace にいれるには
namespace Test {
...
}
namespace Test {
void func(){ printf("func" ); }
}
// call する
Test::func();
std もこのとおりになっている
Namespace は [ まさに ] その空間を探す. メタファは電話番号の市外局番.
lass を利用すると自動で Namespace に収まる
長い Namespace は別名をつけることが可能. ( namespace の alias )
namespace sName = long-long-long-name;
using namespace sName;
using namespace XXX; と言うときは XXX が先にないと CMP に怒られる
namespace 内で class の宣言をした後に, 定義( 実装 )をする場合は namespace は不要らしい.
-> あっても問題はないらしい. -> なぜか ?
CMP からしてみれば, XXXさんち( using )を利用しているならば, わかるということかな ?
class 定義内の class 定義は, 親クラスの namespace に収まる.
class Foo
{
// 当然 public section にある必要がある.
public:
class Bar {
public:
Bar(){ printf("Foo::Bar ctor" ); }
} b;
};
class Client {
public:
void main() {
Foo::Bar b;
}
}
POINT
namespace xxx{} 内で宣言. 定義されたものは. xxx::YYY となる.
内部にいる限りは, local の YYY が参照される.
会社内で, さとうさんと言えば, 会社::さとう を指すという自然な流れ.
なければ, さらに外の Scope に検索が広がる.
// class なしでも利用可能.
namespace OTONARISAN {
void aruku(){...}
}
void main() {
OTORINASAN::aruku();
}
WARNING
次の case は ERR: ( using namespace は使いすぎは注意. )
namespace A組; // A 組のこと
namespace B組;
using A組::さとうさん; // これは通じない
void func() {
さとうさん s; // ERR: どっちの ?
s.walk();
}
POINT
基本ルールは 現在の namespace から検索される
例外があって, 基底クラスがあれば, そちらが優先
class 内での宣言は不可能
namespace は コンパイル後の symbol として修飾される
-> ?f@doodle@@YAXXZ ( ie. 名前空間は言語仕様 )
// Class の定義と宣言に関する考察.
class Foo {
public:
// これは #include するのも含めて, 定義が複数の CMP 単位. ( .cpp )にあっても問題なし.
// setPos() とかで普通に利用している.
void func() {
printf( "impl" );
}
};
// この記述は 1 箇所でないと, Symbol が多重定義といって怒られる.
Foo::func() {
printf("impl" );
}
class 内にあれば, inline ( 要請 )関数と同じ扱いになる. -> 埋め込むので当然定義が必要になる.
cpp に 定義したクラスを AnonymousNameSpace にいれる意味がわからない.
共通ヘッダ. に次の記述をした場合はどうなるか. ?
// common.h
static unsigned int gNr;
// foo.cpp
include "common.h"
gNr ++;
// bar.cpp
include "common.h"
gNr ++;
A:
Compiler Linker 共に問題なし.
#include は文字とおり,
PreProcessor による埋め込みにすぎないことを忘れないこと.
埋め込まれた後の file 単位を想像すればわかりやすい.
// foo.cpp // bar.cpp
static unsigned int gNr; static unsigned int gNr;
gNr ++; gNr ++;
-> ので gNr は 別の Memory 上の領域. ( && File 外からはアクセスできない. )
以上を踏まえて, AnonymousNamespace を考えると
// foo.h
AnonymousNamespace {
class Foo {
};
}
FooDummy は コンパイル単位でアクセス可能 && 別の種類のクラスになる.
■ クラスのネームスペース
クラスもネームスペースをつくる。
class Impl は各クラスのネームスペースに収まる。
だから同じ名前があってもいい。
{{{
class Array {
// Array クラスの Impl
class Impl;
Impl *impl;
};
class List {
// List クラスの Impl
class Impl;
Impl *impl;
};
}}}
■ 無名ネームスペース(AnonymousNamespace)
特定のシンボルをファイル外からアクセスできないようにするために使う。
無名とあるが実際はコンパイラが適当な名前をつける。
仕組みは
__hidden_name__:: という形で [ compile file 単位 ]で, 名前が割り当てられる。
そして using namespace __hidden_name__ とされるので内部リンケージとなる仕組み。
C でいうところの内部リンケージの代用。
void xxx::impl() と同じになる。
// 名前なしでシンボルを定義する。
namespace
{
void impl() {
printf( "call " );
}
}
// 同一ファイル内からはコールできる。
void func()
{
impl();
}
使用側は名前でシンボルを特定できないので, リンクできない
extern void func();
func();
// 非公開のシンボルは名前が分らないのでアクセスできない。
impl();
ヘッダファイルで次の宣言をしておくと、インクルード先のファイル単位で別のクラスが生成される。
// foo.h
namespace {
class Foo {
};
}