クラスを使おう!無名名前空間を利用しよう!
オブジェクト指向言語であるC++においてクラスは基礎的な部品であり、論理構造を抽象化し、ソースコードの見通しを良くしてくれる。
クラスは他の関数ないしクラスのメンバ関数において、実装として局所的に使われるケースがあっても良い。なにもクラスは「再利用されなければならない」''わけではない!''。
つまりヘッダにかかれない−インターフェースとはならない、クラスがあっても一向に構わない。ここでは、このような実装のために使われる局所的なクラスを実装クラスと呼ぶことにする。
// func.h void func();//関数プロトタイプ
//func.cpp #include "func.h" #include <iostream> class FuncImp{ public: void run(){ std::cout << "func!\n" << std::endl; } }; void func(){//関数の実装 FuncImp fimp; fimp.run();//実装クラスに委譲 }
さて上記のような実装クラスを用いることで、処理の実装を簡潔に記述することができる(このことについてはまたいずれ)。ヘッダには書かない実装クラスは積極的に書くべきであるが、上記ソースにはひとつ問題がある。それはクラスFuncImpリンケージが外向けに公開されているために別の翻訳単位で再宣言可能しても、再宣言したクラスはリンカから見逃されてしまうのだ。複数の翻訳単位で同じ名前のクラスが宣言された場合、先に現れたものが優先される。
// main.cpp #include "func.h" class FuncImp{ public: void run(){ std::cout << "main!\n" << std::endl; } }; int main(){ func(); FuncImp fimp; fimp.run(): }
#実行結果 func! func! //main!となって欲しい
main.cpp側では直前に宣言・定義したクラスが使われずに、別の場所(func.h)で宣言・定義したクラスが使われてしまっている。
上のような状態を防ぐには、実装クラスの、宣言・定義を''無名ネームスペース''で囲むことだ。以下のようにする。
//func.cpp #include "func.h" #include <iostream> namespace {//無名ネームスペース class FuncImp{ public: void run(){ std::cout << "func!\n" << std::endl; } }; }//無名ネームスペース閉じ void func(){//関数の実装 FuncImp fimp;//とくに型の参照はそのまま fimp.run();//実装クラスに委譲 }
無名ネームスペースを活用することで、クラスの名前を外に公開することがなくなり、安心して実装クラスを宣言・定義することができる。