ローカルクラスとインナークラスについて
特徴
- ローカルクラスもインナークラスも外のクラスメンバにprivateなメンバにもアクセスできる
- ローカルクラスはテンプレート引数に使えない(コンパイラによっては使えるかも)
ローカルクラスとインナークラスの定義
外のクラスにアクセスできるサンプルコード。
#include <iostream> template<class Printable> void printAny( Printable& printable ) { printable.print(); } class Hoge { public: class InnerClass { public: InnerClass( const Hoge& hoge ) :m_Hoge(hoge) {} public: void print() { std::cout << m_Hoge.m_Text << std::endl; } private: const Hoge& m_Hoge; }; public: Hoge( const char* pText ) :m_Text(pText) {} void print() { std::cout << m_Text << std::endl; } void print_localClass() { class LocalClass { public: LocalClass( const Hoge& hoge ) :m_Hoge(hoge) {} void print() { std::cout << m_Hoge.m_Text << std::endl; } private: const Hoge& m_Hoge; }; LocalClass localClass( *this ); // ローカルクラスもテンプレート引数できないコンパイラもある //printAny(localClass); } private: std::string m_Text; }; int main (int argc, const char * argv[]) { // insert code here... Hoge hoge("hogehoge"); Hoge::InnerClass innerClass(hoge); hoge.print(); hoge.print_localClass(); innerClass.print(); // templateの引数にも出来る printAny(hoge); printAny(innerClass); return 0; }
これっていつ使う?
関数オブジェクト(または特定のクラスの子クラスを)を作りたい、かつ外から見られたくない(privateなクラスにしたい)というときのやり方は
- ローカルクラスを使う
- クラス定義をcppに書いて、そのソースファイルでしか使えないようにする
- privateなインナークラスを定義する
の三つが可能性としてあると思う。
ローカルクラスを使った方が場合
特定の関数の中だけで必要な場合はローカルクラスを定義して対応するのがいいと思う。
処理が長くなる場合は、コードの読みづらくなるのでcppファイルに定義をする方がいいかもしれない。
しかしながら、外のクラスにアクセスした方が都合がいい場合はローカルクラスにせざる得ない。
クラス定義をcpp側に書く方がいい場合
複数の関数で同じクラスを使い回したいときは、cpp側に書くか、privateなインナークラスを定義するかの
二つの戦略が取れる。ヘッダーファイルが他のプログラマーとのインターフェイスと考えれば、
privateなメンバは本来見えなくてもいいもの。出来るだけ隠蔽したいと思うので、cpp側に書くことのが
好み。
privateなインナークラスを使った方がいい場合
複数の関数で同じクラスが使いたいが、ローカルクラスのように外のクラスにもアクセスしたい場合は
インナークラスを使うのがいい。
また、ヘッダーに定義を書く場合はインライン化が期待出来る(はず)
あと無名インナークラスについて
class Hoge3 { public: class { public: std::string text; } m_Member; public: Hoge3() { m_Member.text = "hogehoge"; } };
↑のように定義できる。クラス名を書かなくても定義できる。後ろにメンバ名をつけるとクラス名のない
クラスが定義できる。
大きなクラスになってしまって、処理を分割したいときに使えそう。
リファクタリングの1stステップとしてたくさんあるメンバ変数とメンバ関数を
ひとまとまりにして、その後、正式にクラスとして抜き出すという作戦が使えそう