読者です 読者をやめる 読者になる 読者になる

Life, Education, Death

プログラミング以外でも思ったことをつらつらと書きたい

ローカルクラスとインナークラスについて

特徴

  • ローカルクラスもインナークラスも外のクラスメンバに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;
}

http://ideone.com/B6Tgs

これっていつ使う?

関数オブジェクト(または特定のクラスの子クラスを)を作りたい、かつ外から見られたくない(privateなクラスにしたい)というときのやり方は

  1. ローカルクラスを使う
  2. クラス定義をcppに書いて、そのソースファイルでしか使えないようにする
  3. 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ステップとしてたくさんあるメンバ変数とメンバ関数
ひとまとまりにして、その後、正式にクラスとして抜き出すという作戦が使えそう