トップページ
ひらく | たたむ | ページトップ
↓マウスで反転選択した文字を検索
C++
   
ページ内検索 ページ外検索
検索したい文字を入力して
ENTERを押すと移動します。
\n
[ トップページ ]
[ ____CommandPrompt ] [ ____JScript ] [ ____MySQL ] [ ____Cygwin ] [ ____Java ] [ ____Emacs ] [ ____Make ] [ ____Perl ] [ ____Python ] [ ____OpenGL ] [ ____C# ] [ ____StyleSheet ] [ ____C++ ] [ ____Winsock ] [ ____Thread ] [ ____VisualStudio ] [ ____C ] [ ____Win32API ] [ ____Lua ] [ ____PhotoShop ]
ヘッダ検索

___

■ STL








___

■ 共通

コンテナクラスも 参照渡し可能 ( object なので当然 ) void testFunc( vector< int> &list ) ...; } 関数ポインタを渡す際は static でない mem func は不可能 理由は obj がない状態では 関数のアドレスが決まらないから Container の memory を確保するために, new が call される. それを選択させるのが, Allocator 何か処理をさせる場合は, ctor, method 経由で渡すことが大事
___

■ コンテナクラス

DESC 他のオブジェクトの集まり( コレクション )のクラス List, Set, Dictionary
___

■ コンテナにオブジェクトをいれる

コンテナにいれる物は オブジェクトか、そのポインタのどちらかになる。
     値のコンテナ
     ポインタのコンテナ
また、中身をそろえる、そろえないで2種類できる。 Java のように共通の基底クラス Object から派生したクラスをすべて入れることもできるが 有効なのは、特定の基底クラスから実装した派生クラスのみをいれること。 WARNING ポインタをコンテナにいれる場合は 複数のポインタからインスタンスが参照されることになる。 そのため、delete した後のインスタンスを参照する危険性がある。 対策として SharedPointer などが使える。 または注意深く、オブジェクトを管理する。 REFERENCE SharedPointer
___

■ vector

SYNTAX void resize( size_type _Newsize )
      vector< int> b(7); // constructor の引数として、配列の要素数をとる
      vector< int> b(7, 5) // 5 で初期化
___

■ 追加

SYNTAX iterator push_back( iterator )
___

■ 削除

SYNTAX iterator erase( iterator ) DESC iterator がさす要素を削除 && 配列を自動で詰めなおす && 次の iterator を返す
    vector< int> a;
    
    a.push_back(1);
    a.push_back(2);

    vector< int>::iterator it = a.begin();

    // 先頭の要素を削除    
    a.erase( it );

    // 先頭から2番目を削除
    it++;
    a.erase( it );
___

■ サイズ

SYNTAX void resize( size_type nr ) DESC 要素数を変更する。
___

■ 挿入

SYNTAX iterator insert( iterator, const T& ) : iterator がさす "要素の前" に挿入 && 挿入した要素を指す iterator をかえす.
      [0, 1, 2, 3, 4, 5, 6, 7]
       ^
       |
            itr
      
      itr = v.insert( itr, 8 );
      [8, 0, 1, 2, 3, 4, 5, 6, 7]
       ^
       |
___

■ 参照

SYNTAX reference operator [](size_type n); const_reference operator [](size_type n) const; reference at(size_type n); const_reference at(size_type n) const;
    // コンテナの i 番目の要素を v という別名で参照. 
    int &i = a[i];
    // 実は次のことと同じ. ( 参照を取得するから代入可能.  )
    i[0] = 10;
コンテナクラスの代入 OK らしい( 要素が正しく operator=() の定義が必要 ) erase() をしても vector::end() は不変 // WARNING: itr ++ 扱い for ( ; itr != itrend; ) { if ( itr->flag ) { itr = pnt.erase( itr ); } else { itr ++; } }
    {
      vector<  vector< int> > foo;
      
      vector< int> bar;
      bar.push_back(1);
      bar.push_back(2);
      bar.push_back(3);

      vector< int> a;
      a.push_back(11);
      a.push_back(12);
      a.push_back(13);
      
      a.push_back(bar);
      a.push_back(a);

      printf(foo[1][2]);  // = 13
    }     
___

■ multimap

POINT lower_bound(); Desc 指定した値 [ 以.上 ] の要素が最初に現れる位置を返す, count(); // x をキーに持つ要素の数を返す。 size_type count(const Key &x) const;
___

■ map

キーと値の対応表を表現するときに使う。 POINT 検索 O( log N )なので、vector, list と比較すると高速に検索できる。 連想 container map< key, val > key で sort されて格納( name でも sort ) [KEY] = VAL; // xxx.ini POINT listXXX.insert( make_pair( oneObj, twoObj ) ); WARNING iterator を移動しながらの 削除はできない

    map< string, int> l;
    l.insert( make_pair("a", 10) );
    l.insert( make_pair("b", 11) );

    for( map< string, int>::iterator i=0; i!=l.end(); i++ ){
      l.erase( i );     // ERROR
    } 
___

■ 挿入

    tbl.insert( make_pair(key,val) ); 
    tbl[ key ] = val;
___

■ 削除

    // iterator の指す要素を削除して次の要素をさす iterator を返す
    iterator erase( iterataor i );
    size_t erase( key );
// key を指定して削除 map< string, int> m; unsigned int nr = m.erase("foo"); nr = 0; ならば消せていない
___

■ 検索 参照

       Tbl::iterator i;
      i = tbl.find( 2 );
T &map::opeartor []( const Key & ) DESC キーに対応する要素を参照 左辺値になる場合に、同じ値を持つ要素がないときは k をキーに持つ右辺値を挿入
    // val に対して, DefaultCtor が起動するらしい. 
    val = tbl[ key ];

    typedef map<  int , string > List;
    List tbl;

    tbl[0] = "aaa";
    tbl[1] = "bbb";
    tbl[0] = "ccc";
  
    List::iterator i = tbl.begin();
    for( ;i != tbl.end(); i++ ){
      printf( i->second.c_str() );
    } 
  
    // "bbb"
    printf( tbl[1].c_str() );

    // ""
    printf( tbl[3].c_str() );
___

■ list

STL のリストは双方向リスト。 POINT 追加、削除は O(1) 参照は O(N) 追加、削除は早いので、頻繁に追加、削除をする場合に使う。 ただしアクセスは配列のように O(1) でアクセスできない。 DESC iterator insert( iterator, const T& ) : vector< T> 同様. operator [] は不可
___

■ 追加

    list<  int > l;

    l.push_back( 1 );
    l.push_front( 2 );

rbegin() sort( bool func(T &, T &) );
___

■ 削除

SYNTAX void pop_back(); void pop_front(); iterator erase( iterator ); リストから削除するときは, イテレータの指す場所から削除する。 erase() は削除した次の要素を指すイテレータを返す。
    list<  int > l;

    l.push_back( 1 );
    l.push_front( 2 );

    list<  int >::iterator  i = l.begin();

    for ( ; i != l.end(); i++ ) {
      if ( *i == 2 ) {
        l.erase( i );
        break;
      }
    }
WARNING erase しながら イテレートをする時は erase で返す iterator を受け取ること。 削除すみのリスト要素に対して ++ をすることになるため。
    for ( ; i != l.end();  ) {

      printf( "%d\n", *i );

      if ( *i == 2 ) {
        i = l.erase( i );
      }
      else {
        i++;
      }
    }
pop_front(), pop_back() は要素を返さずに削除するだけ。
    list<  int > l;

    l.pop_back();
    l.pop_front();


    // 値がほしければ 参照のメソッドをつかってコピーをとる。
    int i = l.front();
    l.pop_front();

___

■ 参照

SYNTAX T &front() const T &front() const T &back() const T &back() const DESC リスト内の要素の参照をかえす。
    list<  int > l;

    l.push_back( 1 );
    l.push_front( 2 );
    
    // 2
    const int &ci = l.front();

    int &i = l.front();
    i = 3;

    {
      // 3
      const int &ci = l.front();
      // 1
      l.back();
    }    
___

■ ソート

    // a <  b <  c ... //小さい順 
    bool cmp( int &a, int &b ){ return a <  b };
    list< int> li;
    li.sort( cmp );

pop_front | pop_back ; 要素がなくなる ( list の中身がかわるよ ) remove( val ) : val と一致するすべての要素を削除. ( ptr OK ) Predicator( Yes/No 関数. ) を利用して, loop する. bool update_and_delete(Object* p) { p->update(); if( p->isDelete() ) { delete(p); return true; } return false; } do { // Predicator を渡すことで, list を前後にわける. // [1][1][1]....[0][0]...[0] // . ここを返す. // そして erase する. objs.erase( remove_if( objs.begin(), objs.end(), update_and_delete), objs.end() ); } while( !objs.empty() ); // リストが空っぽになったら終了
___

■ set

POINT データの重複を許さない集合のこと。 重複をしないリストをつくるときに便利。 追加, 削除 O(logN) 検索 O(logN) 重複をしない単語リストをつくる
    typedef  set<  String >  StringSet;

    StringSet a;

    string word;

    // 単語を登録する
    while ( cin >> word ) {
      a.insert( word );
    }
___

■ コンテナへの操作

    #include< algorithm>
___

■ std::find

SYNTAX find( first, // 検索開始位置のイテレータ end, // 終了位置のイテレータ T &value // 検索する値 ) DESC value と同一の値を指す iterator をかえす end を指すイテレータを返す。
   int i = 0;

   vector<  int >::iterator itr = std::find( 
        tbl.begin(),
        tbl.end(),     // 終了
        i           // 探す要素
        );
___

■ std::count

SYNTAX find( first, // 検索開始位置のイテレータ end, // 終了位置のイテレータ T &value, // 検索する値 result )
___

■ std::remove

SYNTAX find( first, // 検索開始位置のイテレータ end, // 終了位置のイテレータ T &value // 検索する値 ) DESC 指定した範囲で value と一致する値を削除する
    vector<  int > v( 10 );
    std::fill( v.begin(), v.end(), 7 );

    std::remove( v.begin(), v.end(), 7 );
    
___

■ std::fill

SYNTAX find( first, // 検索開始位置のイテレータ end, // 終了位置のイテレータ const T &value )
    vector<  int > v( 10 );
    std::fill( v.begin(), v.end(), 7 );
___

■ std::replace

SYNTAX replace( first, // 検索開始位置のイテレータ end, // 終了位置のイテレータ const T &src // const T &dst // ) DESC first から end の範囲で src の値を dst に変換する。
    vector<  int > v( 10 );
    std::fill( v.begin(), v.end(), 7 );

    std::replace( v.begin(), v.end(), 7, 10 );

___

■ std::unique

SYNTAX find( first, // 検索開始位置のイテレータ end // 終了位置のイテレータ ) DESC first, end までの区間で重複を取り除く。 WARNING unique を実行するには、コンテナの要素は sort されている必要がある。
    vector<  int > v( 10 );
    std::fill( v.begin(), v.end(), 7 );

    // sort してから
    std::sort( v.begin(), v.end() );

    // 重複をとる
    std::unique( v.begin(), v.end() );
___

■ std::sort

SYNTAX find( first, // 検索開始位置のイテレータ end // 終了位置のイテレータ ) DESC first, end までの区間をソートする。 中身はクイックソート。 REFERENCE qsort

    std::random_shuffle( v.begin(), v.end() );

    std::sort( v.begin(), v.end() );

    for( int i=0; i< v.size(); i++ ){
      cout < <  v[i] < <  endl;
    } 
POINT 自作のクラスもソートできる。 この場合は < 演算子のインターフェイスを持つことが条件になる。 昇順( ちいさい順 )にならべるには、 A < B ときたら A が小さいときに true を返すようにする
    class vec2 
    {
     public :
      bool operator <  ( const vec2 &rhs ) {
        bool ret = length() <  rhs.length();
        return ret;
      }

      float length() const {
        return x*x + y*y;
      }

      vec2( float _x, float _y ) : x(_x), y(_y){}

      void toString() { 
        printf("%f %f\n", x, y ); 
      }

     private:
      float x, y;
    };

    
     vec2 v0( 1, 2 );
     vec2 v1( 2, 2 );
     vec2 v2( 0, 2 );

     std::vector< vec2> a;
     a.push_back( v0 );
     a.push_back( v1 );
     a.push_back( v2 );

     std::sort( a.begin(), a.end() );

     for( int i=0; i< a.size(); i++ ){
       a[i].toString();
     } 
___

■ std::binary_search

SYNTAX bool binary_search( first, // 検索開始位置のイテレータ end, // 終了位置のイテレータ const T &value // 検索する値 ) DESC first, end までの区間で binary_search をして、その結果を返す。 REFERENCE bsearch

    set<  int > a;

    bool ret = binary_search( a.begin(), a.end(), 1 );

___

■ random_shuffle

指定した配列をランダムに並びかえる。
    const int N = 1000;
    int i = 0;

    int *a = new int[ N ];

    for( i=0; i< N; i++ ){
      a[i] = 0;
    }  
    
    std::random_shuffle( a, a + N );
___

■ テンプレート(Template)


___

■ Template する場所を見抜く方法

[ 処理が同じ ]で [ Data 型が異なる ]ところ. -> 逆に関数とは, 特定の処理をひとくくりにすること. Instanciate した時点で既に, template ではないことに注目. 次のような記述もえきる。
     struct Tbl
     {
       string name;
       void *(*create)();
     }; 

    Tbl tbl[] = {
      {
        {"Chara", create<  Chara > }, 
      }
値を交換する処理は、型が違うだけで処理は同じ。 オーバーロードした瞬間にテンプレートが利用できないか考えること。 コンパイラにやらせてしまう。
    int swap( int &a, int &b ) {
      int t = a;
      a = b;
      b = t;
    }

    float swap( float &a, float &b ) {
      float t = a;
      a = b;
      b = t;
    }
型をパラメータ化して関数のテンプレートをつくる。
    template < typename T>
    void swap( T& a, T& b )
    {
        T t = a; 
        a = b; 
        b = t;
    }  

    swap(x, y);      // コンパイラが自動で生成する。
    swap< int>(x, y); // 型を明示する場合は int をつける。
___

■ 関数テンプレート(FunctionTemplate)

SYNTAX [ class | typename ] keyword 利用する。 template < class type> function-declarator template < typename type> function-declarator template < class X1 , class X2> void println(X1 var1 , X2 var2); 関数テンプレートには2種類の場所で定義できる。
     グローバル関数
     メンバ関数
// template 型であることの宣言 template< class T > T myabs( T a ){ a = a>0 ? a : -a; } // 使用するときは
  int b = -7;
  int n = myabs( b );

  // 明示する
  int b = -7;
  int n = myabs< int>( b );
PrmTpl が返値のみでも OK. -> ただしどの型に対して Instanciate するべきか教える必要がある. -> 関数の後に < >() とあったら, PrmTpl を 明示していると考えよう. template < typename T > T foo() { T data = 0; return data; } Client::main() { int i = func< int>(); } WARNING 引数が複数ある場合は、同一の型がくるとしても template 名を分ける必要あり
    template<  class T1, class T2 >
    T1 Add( T1 a, T2 b ){
      return a+b;
    }  

      int a = 5;
      char b = 3;
      int n = add( a, b );

___

■ クラステンプレート(ClassTemplate)

DESC 意味としては、クッキーの型だと思えばOK 素材( 型 )と処理を分離して考える 内部的な型だけを変換していると思えばOK , あくまでクラス定義しているにすぎない 次のように考えるとわかりやすい template< XXX > を除去 2. XXX -> 具体的な型に変換 [ vector ] を例に考えてみる.
      vector<  myInt > foo;   // int 型 vec ( 使用する際は, < 型> とする )
      
      template < T> 
      class vector{
         T foo;
      }
// 変換後( こう見ればよい ) class vector{ int foo; } // 使用する際は vector< int > aaa; // [ int型 vector クラスの aaa を生成した ] と考える
___

■ 型だけでなく 値もパラメータとして受け取れる

非型パラメータを指定する場合は型名は実際の型にする。

    // 固定サイズの配列
    template < typename T, int N>
    class Array {
      public:
        void push_back( const T &data ) {
          data[ p ] = data;
          p ++;
        }

        Array() : p(0){}

      private:
        T data[N];
        int p;
     };
使うときは非型パラメータの部分は値を指定する。
    // int 型 10 要素の固定配列
    Array< int, 10> a;
    a.push_back( 5 );
整数型・列挙型の値 オブジェクトへのポインタ・参照 関数へのポインタ・参照 メンバへのポインタ POINT template の型を固定することもできる
//
// unsigned にすることで,負数を避けることが可能. 

// アラインメントをそろえる
      template<  unsigned int BASE, typename T >  
      T floor( T x ) 
      {
        return static_cast< T>( ((x) + ((BASE)-1)) & ~((BASE)-1) );
      }

    // 利用する時は
    roundUp< 16>( 10 );
___

■ テンプレートパラメータにデフォルト値を設定する

デフォルト値を指定するには、デフォルト引数と同様に = TYPE とする。 STL クラスはアロケータのデフォルトとして std::allocator< T> をもつ。
      template < class T, class Allocator = allocator< T> >
      class vector
      {
        ...
      }

そのため利用するときは、要素型を指定するだけでよい
    vector<  int > v;
自作のアロケータがある場合は、指定することでメモリ処理をカスタマイズできる。
    class MyAllocator {

    };

    vector<  int, MyAllocator > v;
___

■ template 化するコンパイラの立場で考えてみる

template < class T> // 以下は汎用クラスだよ. ( 未知の型がくるよ. とりあえず T にするよ ) template < [typelist] [ , [ arglist]] > declaration パラメータ化した汎用関数、または汎用クラスだよー と compiler に通知. declaration : 関数またはクラスを宣言 typename nameType 未知の識別子の[ 型 ]だよ- とコンパイラに通知( class keyword でも OK )
___

■ 特殊化する

DESC ある特定のテンプレート型の場合だけ特別仕様にする時につかう。 特定の template 引数用に定義すること. -> 特殊化する前に、汎用 template を定義する必要あり XXX 型の場合の特別バージョンという意味。
    template< >   
    void func<  XXX >{} 
特化するには, 汎用のテンプレート( 定義 | 宣言 )が必要になる。
           // 基本は CMP 単位で処理されて, 

           // あ !  foo という FunctionTemplate があるな... 
           template <  typename T > T foo();

           // これは float 型の場合に利用する関数だな...
           template < > 
           float foo< float>()
           {
             float data = 0.0f;
             printf("special");
             return data;
           }            

           Client::main() {
              // foo はたしか, FunctionTemplate で float 型の特殊定義があったな... 
              // よし今回はこれを使おう. 
              foo<  float >();
           }
引数の数は合わせる必要があるらしい. 宣言のみ && 特化の場合は CMP は通るが, LINK で落ちる. ie. 特化は別 Module でしてもいいことになる. -> 要は, FunctionTemplate の宣言は, パラメータ数のみが一致すれば CMP OK な汎用宣言だと考えよう.
       template < typename T>
       void copy(T* dst, const T* src, size_t size)
       {
         for(size_t i = 0; i <  size; i++) {
           dst[i] = src[i];
         }
       }
// 特殊化( 型を指定しない -> < > , 逆に template< > とある場合は, template 本体がある. ) // XXX の場合と言い換えよう template < > void copy< char>(char* dst, const char* src, size_t size) { memcpy(dst, src, size); } template < > static inline ErrorCode DEPRECATED createInterface( pad **unknown, uint32_t no) { return interfacebase::impl::createInterfaceImpl(unknown, no); } // 部分特殊化 // 元となるテンプレート template < typename T1, typename T2, int I> class A { ... }; // 部分特殊化したもの template < typename T, int I> class A< T, T*, I> { ... }; template < typename T1, typename T2, int I> class A< T1*, T2, I> { ... }; template < typename T> class A< int, T*, 5> { ... };
___

■ template 全般

Class, 関数の定義をパラメータ化する ( Java にない便利機能 ) 定義を抽象化( Grouping )する. 通常は. 宣言と定義を header にする。 宣言のみでは LINK できない。 コンパイル時にコードを生成するため、コンパイル単位で定義が必要になるため。 基本的に define 同様の置換がされるが, PreProcessor ではなくコンパイラがコードを生成する 汎用 class( 型 )だけでなく, 固定型も使用可能. = をつけると Default 設定. ( = とでてきたら Default で [い.く.つ] と考えること ) 実際に使用して == ( PrmTpl )を与えて, 評価されるらしい.
   //  MethodTemplate も作成できる
      class Foo {
       public:
        template<  typename T >
        void func( T i ) 
        {
         cout < <  i < <  endl;
        }
      }; 
      
      foo.func( 10.0f );
      foo.func( 10 );
      foo.func( "10" );
FunctionTemplate と 通常関数が 同名ならば, 通常関数が優先される. -> ただし TypeCheck して固定関数にあうものがなければ, FunctionTemplate から生成されるよ. template< typename T > void func( T i ) { cout < < i < < endl; } // 固定関数. void func( int i ) { cout < < "fixfunc " < < i < < endl; } { unsigned int i = 10; func( i ); // FunctionTemplate がよばれる. } 前方宣言も OK bCls が ClassTemplate の場合, bCls の変数はクラスを明示しないとアクセスできない. ( 言語仕様. GCC は準拠. VS++ では無視. )
     class Object {
        // ctor という Method を template 化した
        template<  typename T >
        Object( T ty ){ ... }  
     };

     int i;     
     Object o( i );
template < class T, int N = 1> // Default 1 && Arg2 は int であると CMP に通知. class Allocator { } -> FuncTemplate には利用できないらしい. ( なんで ? ) Template 内容に矛盾があれば, コンパイル時にエラーがおきる
       // SmartPtr を 実装.
       class Resource
       {
   public:
     void use(){ /*参照カウンタ+1*/ }
     void release(){ /*参照カウンタ-1と解放*/ }
       };

       template < class T>
       class SmartPointer
       {
   T *m_pointer;   // 本体.
        public:
   // INIT
   SmartPointer(T *p)
     :m_pointer(p) {
   {
       // 置換した状態で矛盾があれば CmpErr
       m_pointer->use();
   }

   ~SmartPointer() {
     m_pointer->release();
   }
       }
___

■ template 具体例

DESC setter, getter の template 化 // prop object template < class T> // 以下は汎用クラスだよ. ( 未知の型がくるよ. とりあえず T という名前にするよ ^/ ) class typeProp : public absProp { public: virtual eProp getType() const; // accessor という処理は同じ. vitual T getVal( base *p ) = 0; vitual void setVal( base *p, T val ) = 0; };
___

■ 色々実験してみる

Q: PrmTpl を引数にとらない関数は FuncTemplate にできるか ? template< typename T > void func() { T i = 20; printf( i ); } func< int>(); // OK: 文として矛盾が起きないなら問題なし. func(); // ERR: TemplateParamter がわからない. < T > と教えてあげる. func< Foo >(); // ERR: ここで本当に instantiated しているらしい. Foo i = 20; // ERR func(); // ERROR: no matching function for call to `func()' func が具体化されていいない証拠.
___

■ refcnt : 参照カウンタ

DESC object 自身が他から, 参照される個数をカウントする. 0 になれば, 不要ということで解放. -> new した時点で 1. POINT 2. create() 作成 && release() 破棄 3. Model から参照されている際に、削除できないようにリソースという扱いにしている ( ie. new, delete < -> create(), release() なんだ ) 4. mdl->release() は mdl というポインタ( 矢印 )から Object(Resource)を離すイメージ // delete のかわり、[ 参.照.し.な.い.よ ] と宣言. virtual void release(){ counter --; if ( counter == 0 ){ delete this; } } // これを呼ばないとだめなのが, メンドイ. void use(){ counter ++; } // 作成時に cnt = 1 Resource() : m_counter(1), m_name(0) { } WARNING obj が相互に 参照する場合は, 循環がおき, mem leak がおきるので注意 任意の数値を文字列に変換する関数テンプレート。
    #include < iostream>
    #include < string>
    #include < sstream>

    template< class T> 
    string numberToString(T n)
    {
        stringstream s;
        s < <  n;

        return ss.str();
    }
___

■ 名前空間(NameSpace)



      単に宣言された領域
      名前空間はシンボルのスコープ( 見える範囲 )を決定する。
      名前空間は異なる 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 でいうところの内部リンケージの代用。
    static int cnt;
void xxx::impl() と同じになる。

  // 名前なしでシンボルを定義する。
  namespace
  {
    void impl() {
    printf( "call " );

    }
  }      

  // 同一ファイル内からはコールできる。
  void func()
  {
    impl();
  }

使用側は名前でシンボルを特定できないので, リンクできない
    extern void func();

    func();

    // 非公開のシンボルは名前が分らないのでアクセスできない。
    impl();

ヘッダファイルで次の宣言をしておくと、インクルード先のファイル単位で別のクラスが生成される。
  // foo.h
  namespace {
    class Foo {
            
    };  
  }
___

■ 前方宣言(ForwardDeclare)


    クラスの型ではなく、クラス情報( シンボル )のみで済む場合に宣言することで
    コンパイラに知らせる。

    Bar 型のポインタのため、 Bar の定義(構造)は知らなくてもよい。
    そこで、 class Bar; としてシンボルの存在だけを通知する。

    class Bar;
    
    class Test {
      Bar *p;
    };
namespace 内のクラスを宣言する。
    namespace Foo{
        class Bar;
    }
___

■ FunctionObject(ファンクタ)


  DESC
    function(関数) object といわれるもので
    Cでいうコールバック関数ポインタの働きをする
      
    関数のように動作する Object のこと
    演算子 overload のうち、() をoverload したもの

  POINT
    使いどころ
    より優れたコールバックを記述すること.
    C などの手続き型プログラミング言語にコールバックは関数へのポインタによって実現することができる
    コールバックの内外に状態変数を渡すことが難しい

    strategy デザインパターンの完全な具現化であり、抜き差し可能な振る舞いを促進するもの。
    STL では Template による. Functor を多用している


      operator=()
      operator()()
      
      // 関数 object
      class Cout()
      {
        public:
          void operator()( int num ){ 
              cout < <  num < <  endl;
          }
      };

      // Client  
      int main(){
          Cout func;
          func( 5 );   // call back を呼ぶ
      }
      

      // template 化する
      template <  class T >
      class Cout()
      {
        public:
          void operator()( T num ){ cout < <  num < <  endl; }
      };      

      std::for_each( c.begin(), c.end(), Cout< float>() );      
      -> 
      どんな std:cout() に対応できるものならば、すべて可能 ( Template の原則 . )
      STL と組み合わせることで、より強力な tool になる


    // cpp の callback との比較
    int comp_func( int a, int b )
    {
      return a > b;
    }

    // functor
    class compCls
    {
    public:
      operator()( int a, int b ){
        return a > b;
  }
    };

    // 宣言
    template < class compFunctor>
    void sort( int *p, int nr, compFunctor c );
    
    // usr
    int main()
    {
      int data[] = {0, 1, 2};
      compCls func;      // 上記 cls を使用
      sort( data, 3, func );

      // 使用する際は 
      func(); とする ?
    }     

    // 二つの要素の順序関係を定義するコールバック関数を用いて並べ替えを行うルーチンの例
    /* Callback function */
    int compare_function(int A, int B) {
      return (A <  B);
    }    
    
    // C の並べ替え関数の定義
    void sort_ints(int* begin_items, int num_items, int (*cmpfunc)(int, int) );    


   int main() {
       int items[] = {4, 3, 1, 2};
       sort_ints(items, sizeof(items)/sizeof(int), compare_function);
   }    

   // C++ では通常の関数の代わりに、operator() メンバー関数を定義して 関数呼び出し演算子をオーバーロードすることで、
   // 関数オブジェクトを利用できる
   class compare_class {
     public:
     bool operator()(int A, int B) {
       return (A <  B);
     }
   };

    // C++ の並べ替え関数の定義 -> template になっている. 
    template < class ComparisonFunctor> 
    void sort_ints(int* begin_items, int num_items, ComparisonFunctor c);


    int main() {
        int items[] = {4, 3, 1, 2};
        compare_class functor;
        // PtrFunc ではなく, Object をわたす.
        // Object なので, VarMem, FuncMem にアクセス可能.
        sort_ints(items, sizeof(items)/sizeof(int), functor);
    }


    // Functor を別の用途で使ってみる. 
    functor_class Y;
    int result = Y( a, b );    

    
    // Inline 化できるため, C の PtrFunc よりも性能がよい. 
    struct IncrementFunctor {
      void operator()(int&i) { ++i; }
    };

    // 通常の関数による Increment 
    void increment_function(int&i) { ++i; }

    template<  typename InputIterator, typename Function >
    Function for_each(InputIterator first, InputIterator last, Function f) {
      for ( ; first != last; ++first) {
        f(*first);
      }

      return f;
    }

    int A[] = {1, 4, 2, 8, 5, 7};
    const int N = sizeof(A) / sizeof(a[0]);

    for_each(A, A + N, IncrementFunctor());
    for_each(A, A + N, increment_function);    


    // 状態も保持できる.     
    #include < iostream>
    #include < iterator>
    #include < algorithm>

    // 要はクラス名が関数名になる.
    class countfrom 
    {
      private:
        // 状態. 
        int count; 
      public:
        countfrom(int n) : count(n) {}
        int operator()() { return count++; }
    };

    int main() {
      std::generate_n(std::ostream_iterator< int>(std::cout, "\n"), 11, countfrom(10));
      return 0;
    }
___

■ const


___

■ const

定義 定数であることをコンパイラに宣言する。( ANSI C 規格 ) 変数の前に記述する修飾子、その変数が定数であることを宣言する 文字列リテラルは、静的な領域に確保 静的な領域は Read Write, Read Only の領域に分かれる 文字列リテラルの領域に書き込みをすると、 segmentation fault を起こして処理が終了

    // コンストなオブジェクトは初期化の時点のみ値を指定できる。
    const a=6; 

    // コンパイラがエラーを検出してくれる。
    a++;
ポインタの const は宣言する場所で意味がかわる。

    // pが指す内容を変更できないp自体は変更可能
    const char *p="abc"; 
    char const *p="abc"; 

    // p自体の変更は不可pが指す内容を変更可能
    char * const p="abc"; 
___

■ const 記憶クラス

DESC コンパイラに変数の変更をしないことを宣言する。 目的は、オブジェクトを間違って変更しないようにチェックしてもらうこと。 POINT コンパイルの時点でのチェックなので、実行時のコストは0になる。 プログラムの安全性を高めるために積極的に使うといい。 指定したオブジェクトに変更をしないつもりならば const 宣言をする。 これによって不意に変更をしたときにコンパイラが怒ってくれる。
    // path オブジェクトは変更しない意図であることを宣言する。
    writefile( const string &path ) {


      // ERROR
      path = "";
    } 
WARNING const 表明は早期にすること。 他のメソッドに連鎖的に影響をするため。
___

■ mutable(ミュータブル)

DESC const method に対して, 例外的に値の変更を許す宣言のこと。 mutable のついたメンバは const なメソッド内で変更されてもコンパイラは許可してくれる。 使用する側からしてみれば Client から見て, "変更してもわからない値" を変更するために使う object の振る舞いがこの変数に依存しない場合に有効
    class を MultiThread Safe にするために利用( mutex を mutable にする )

    class Camera {

      public:
        // Matrix 値を参照するだけのため, const
        const float *getMatrix() const{
          if ( isDirty ) { 
            data = recalc(); 
            isDirty = false; 
          }
          return data;
        }

      private:
        // 再計算フラグは const メソッド内でも変更を許可してもらう。
        mutable bool isDirty;      // camera の振る舞いに関係なし
    };

___

■ メソッドにconstをつける

メソッドに const をつけるのは、そのメソッドが オブジェクトを変更しないという約束をすることになる。
     inspector
     mutator
    class Stack {
      // オブジェクトの状態をかえるので const ではない。
      int pop();

      // 要素数を教えるだけなので const
      int nrElement() const;
    };
const なポインタ、リファレンスは、変更できないことを約束しているオブジェクトなので inspector のメソッドのみが使える。
    void test( const Stack &stack ) {
      stack.nrElement();

      // コンパイラに約束が違うと怒られる。
      stack.pop();
    };

___

■ C++ 引数の省略化


  C++ は (int foo, bool flag=0L ) とすることで引数を省略できる

  POINT
    C++ はC の仕様を内包する。( malloc など )
    しかしC のクラスを含む構造体をmalloc した際の挙動は不安定

___

■ Default引数の禁止

コンパイルエラーにかけるため、基本はデフォルト引数は利用しない。
    void func( void *a, void *b = NULL, void *c = NULL );

    // 変更した
    void func( void *b, void *c = NULL );

    // a のつもりでいるけど  CMPERR にかからない
    void f( &obj );
参照に対して DefaultArg はできない ? GlobalWork を利用すればいい // 次はできない void func( bCls &a = 0 );
___

■ extern 'C' Linkage


  目的
    C++ から C のコードを呼び出すときに使う。

    c のコードがある    
    void cfunc() {

    }
c++ 側のコードからよびだす。 リンクする場合に次のエラーが表示される
    cl /c  main.cpp

    main.obj : error LNK2019: 未解決の外部シンボル "void __cdecl cfunc(void)" (?cfuc@@YAXXZ) が関数 _main で参照されました。
    main.exe : fatal error LNK1120: 外部参照 1 が未解決です。
POINT コンパイラが生成する外部リンケージ名は, 実際のコード内の関数名とは異なる。 これは C++ のオーバーロードや呼び出し規約を名前に含ませるため。
    void cfunc();

    // C++ コンパイラが生成する名前は
    ?cfunc@@YAXXZ
C 言語の呼び出し規約では, 関数名の頭に _ がついた名前になる。
    _cfunc
そのため C++ 側でかいた cfunc() は リンク時に ?cfunc@@YAXXZ を探しにいくが C 側では _cfunc という名前で公開されているためリンクエラーとなる。 そこで C++ 側で関数を呼ぶ時に _cfunc() という名前で呼ぶようにコンパイラに指示する。
    extern "C" void cfunc();
通常は C で書いているモジュールを提供する側がこの処理をいれる。 C++ コンパイラでは __cplusplus プリプロセッサシンボルが自動で定義される。 これを利用してヘッダに以下の記述をすると, C++ 側では extern "C" cfunc() として公開される。
    // mod_c.h

    #ifdef __cplusplus
    extern "C"{
    #endif

    void cfunc();

    #ifdef __cplusplus
    }
    #endif
    #include "mod_c.h"

    {
      // _cfunc() という外部リンケージ名でコールするようにコンパイラがコードを生成する。
      cfunc();
    }
アセンブラを出力すると外部リンケージ名が見れる。
    // cl /c /FA  main.cpp

    call  _cfunc
    call  ?cfunc@@YAXXZ        ; cfunc
Cpp での関数名の名前の変換を許すか、許さないかをコンパイラに指示 C 言語で記述された Program と Link するよ と C++ コンパイラに教える。 cpp compiler に対して関数の改名を抑止
    // 関数の先頭で宣言する
    extern "C" void foo( void );
1. VarGbl, VarStatic は常駐する. -> plugin load 後は常に値をもって常駐している点に注意 理由: C で書かれた関数をC++ から呼び出すことが困難になるから。 既にあるC のライブラリを勝手に変形されては、呼び出しようがない printf -> xxx_printf() となってしまう。 extern "C" void Cfunc(int); extern "C"{ void Cfunc1(int); void Cfunc2(int); void Cfunc3(int); }
___

■ member 関数ポインタの扱い

WARNING ref VS.80.aspx
___

■ Constructor(コンストラクタ)


    コンストラクタはオブジェクトの生成されるときに必ず呼ばれる関数。
    オブジェクトの初期化をするために使う。

    必ずコンストラクタが実行されるため
    オブジェクトは一貫した形式で初期化できる。
    

    class Test {
    };

    //  インスタンス t が生成されるときに t のコンストラクタが自動で実行される。
    Test t;
___

■ コンストラクトする順番

     基底 ---> 派生の順番に実行される
POINT 建物と同じように考えるとわかりやすい。 基礎ができて -> 飾り が追加される 破棄の際は逆
___

■ 初期化子リスト

クラスのメンバオブジェクトを初期化するには初期化子リストを使う。 コンストラクタ本体の実行の前に、しておくと効率がよい。
    class Test {
      string m_str;

      // メンバオブジェクト m_str を初期化する。      
      Test::Test() : m_str( "" )
      {
        // コンストラクタ本体では空ということも多い。
      }


  WARNING 
      Test::Test()
      {
        // 代入では効率がよくない。
        m_str = "";
      }
    };

コンストラクタはすべてのメンバと、基底クラスを初期化する。 初期化子リストを明示しない場合でも、コンパイラが自動で初期化する。
___

■ コンストメンバの初期化

const メンバは初期化子リストのタイミングのみ初期化できる。
    class Test {
      const string m_str;

      // メンバオブジェクト m_str を初期化する。      
      Test::Test() : m_str( "init" )
      {
        // 初期化の代入は const に反するのでエラーとなる。
        m_str = "test";
      }
リファレンスのメンバも初期化リストで必ず初期化する。
    class Test {
      const string &m_str;

      // メンバオブジェクト m_str を初期化する。      
      Test::Test( const string &s ) : m_str( s )
      {
        // 初期化の代入は const に反するのでエラーとなる。
        m_str = s;
      }


___

■ 初期化子リストの順番

クラスのメンバ変数は、クラスの宣言順に初期化が実行される。
    基底のクラスの初期化 ---> メンバオブジェクトをクラスの宣言順に初期化
    class Test : public Base{
      int i0;
      int i1;
      int i2;
    };

    // 並べた順ではなく 0, 1, 2 の順番で初期化される。
    Test::Test() : i2(2), i1(1), i(0) {}

実際に初期化される順番でかくと間違いをふせげる
    Test::Test() : Base(), i0(0), i1(1), i2(2) {}
WARNING メンバの初期化で別のメンバの値を利用するときは、順番に注意すること。 クラスのメンバの順番を変えただけで、エラーをおこす。
    
    // コンストラクタ本体で代入すれば、順番の依存性を避けることができる。


___

■ DefaultConstructor(デフォルトコンストラクタ)

引数をもたないコンストラクタをデフォルトコンストラクタという。 クラスの constructor は object 生成時に必ずコールされる。 コードで定義しない場合は, コンパイラが自動生成する。
    class T {
      int a;
      public:
        T(){}
    };
      
      
     main(){
        // ローカルのオブジェクト a が生成され、DefaultConstructor( 引数なしのコンストラクタ )コールされる
        T t;
     }
___

■ 配列のコンストラクタ

POINT 配列の場合は、各要素はデフォルトコンストラクタが起動する。
    Test a[10];

    Test *t = new Test[10];
そのためデフォルトコンストラクタがないクラスはコンパイル時にエラーとなる。
    class Test {
      public:
        Test( int i );
    };
初期化したいときは init() などのメソッドをつかって初期化をする。
    Test *t = new Test[10];

    for( int i=0; i< 10; i++ ){
      t[i].init();
    } 
または std::vector を利用すると各要素のコンストラクタを指定できるので便利。
    vector<  Test > a( 10 );

    vector<  Test > a( 10, Test(2) );
REFERENCE vector constructor は object [ 生成時 ]に[ 必ず ]コールされる 返り値をかえせない. ( ObjectAdr を返す必要があるから ) -> Object 自身の型を返す Foo &Foo(); -> ので次のような記述は可能. Foo func() { // Retval を返す際に, CopyConstructor が走る. ie. Foo( const Foo &); return Foo(); } POINT ctor も関数のひとつ. ( Access 制限をうける ) private() にすると自分以外がつくれなくなる bCls::ctor を call するのは dCls::ctor -> ので, protected: bCls::ctor && dCls::ctor ならば次は可能. b *b = new dCls; // ただし B 単体でつくれない. Class の Component は INIT 時に DefaultCostructor が call される. -> Cmp::Cmp( int ){} ど定義してしまえば, 明示的に呼ぶ必要あり.
      class App {
       public:
         App(){
            // 暗黙に c が生成され, Cmp::Cmp() が call 
      #if EXPLICIT
            c();  // CMP が自動生成. ( なければ CMP ERROR )
      #endif       
         }
       private:
         Cmp c;   // Pointer ではなく, object 自身をもつのもあり. ( heap に作成される ? )
            // 内包している分サイズが増大する. 
      };
 
      class foo {
            int a;
              public:
    foo(){ ... }
      }
___

■ CopyConstructor(コピーコンストラクタ)

DESC 引数に自分と同一クラスをもつ コンストラクタのこと。 値渡し ( PassByValue ) で呼ばれる。 同じ型の 別の Object で "初期化" するときに使う
    Foo func() { 
      Foo *f = new Foo();
      return *f;   // ここでコールされる
    } 
POINT 代入演算子と間違えないこと。 インスタンスが生成されるタイミングでコピーコンストラクタは呼ばれる。

    Foo a, b;

    // CopyConstructor
    {
      Foo f( a );
      Foo f = a;
    }

    
    // これはコピー代入演算子
    f = b

    // 値渡し でもコールされる。パラメータ側のオブジェクトが生成されるから。
    // Foo func( Foo );
    Foo d = func( f );
___

■ コピーコンストラクタの自動生成

コンパイラが自動生成する場合は すべてのメンバのコピーコンストラクタを実行する 組みこみ型は bit 単位のコピーがされる。


___

■ コンストラクタ内で別のコンストラクタを呼ぶ

コンストラクタ内で別のコンストラクタをよぶと別オブジェクトが生成される。 コードを共有したい場合は init() などのメソッドを用意する。
    class Test {
      public:
        Test();
        Test();
      private:  
        void init();
    };
___

■ コピーを禁止する

クラスのコピー操作を禁止するには private のアクセスにすることでコピーを利用できないようにする。 File クラスなどはコピーが不要なので、禁止してしまう。
    class File {

      File( string &path );

      private:
        // 利用しないので定義はしない
        void File( const File & );
    }


    File f;
    
    // ここでコンパイラがエラーを教えてくれる。
    File b = f;
___

■ ShallowCopy.DeepCopy

ShallowCopy ポインタだけをコピーすること DeepCopy ポインタの指す参照先も含めてコピーすること。
___

■ コンストラクト方法を制御する

コンストラクタを private 権限にすることで 自分以外がオブジェクトを生成できなくすることができる。 この場合は create() をするスタティックなメソッドを代わりに用意してあげる。 ファイルクラスはロードするクラスのみが管理するようにする。 REFERENCE friend

    class File {

      // ローダにだけ自分の private を公開する
      friend Loader;

      private:
        // 封印する
        File( const string &path );
        ~File();
    };

    class Loader() {
    
      public:
        File *createFile( const string &path ) {
           return new File( path );
        }
        void destoryFile( File * );

    };

    {
      // Loader の管理しない File を作成することができない
      File f;

    }
___

■ 参照型(Reference)



  DESC
    存在する Object の別名.
    実体は Pointer かも ( 実装依存 )
    Ref を利用する際は, 存在する Object は何かを意識しよう. 
    Stack 上の Object の Reference をかえすのは問題あり. 

DESC 
  1. 変数、定数, object に別名をつける。
  1. 関数の引数、返り値に使用。

EX:
   int n = 10;
   int& r = n; // n に別名r をつけたことを意味。メモリ領域を共有している
   r = 7; // n=10;

POINT
  1. 意味論としては, すでに生成済みの object を渡す( 返す )際に利用する
     ( ptr とか意識しないこと )

WARNING 
  1. 参照型の仮引数の場合は cast の際も参照型として cast すること
     ERROR
  getBV( (v3f)max, (v3f)min );
     OK
  getBV( (v3f &)max, (v3f &)min );


___

■ PREFERENCE(C++StdLibrary)



___

■ std::max min

DEP #include< algorithm >
  template < class T>
  inline const T& max(const T& a, const T& b)
  {
    return a <  b ? b : a;
  }

  // overload 型. 
  template < class T, class Compare>
  inline const T& max(const T& a, const T& b, Compare comp)
  {
  return comp(a,b) ? b : a;
  }
  
  ObjFunc は 関数( PtrFunc )のこと 
___

■ IO(入出力)

___

■ ifstream

DESC ファイルを読み込むクラス ( InputFileStream ) fopen と同じように使うことができる。
    #include< fstream> 

    using namespace std;

    // ファイルをバイナリモードで開く
    ifstream in( "test.bmp", ifstream::binary );

    // ファイルオープンのエラーチェックをする
    if ( !in ) {
      printf( "cannot open" );
      exit(0);
    }

    // 末尾へ移動 ( 後ろから 0 byte )
    in.seekg( 0, ifstream::end );

    // 後ろから 4 byte へ移動
    in.seekg( -4, ifstream::end );

    // サイズを取得する
    int sz = in.tellg();
    char *buf = new char[sz];

    // 先頭にファイルポインタを戻す
    in.seekg( 0, ifstream::beg );

    // 指定したサイズを buf へ読み込む
    in.read( buf, sz );

    // 出力
    ofstream out( "dst.txt", ofstream::binary );
小さいサイズのテキストならば operator< < で簡単によめる。
    ifstream in( "test.txt" );

    string str;

    if >> str;
    cout < <  str < <  endl;
___

■ ofstream

出力するには OutputFileStream クラスを使う
    ofstream out( "d:/dst.txt", ofstream::binary );


    int i;
    out.write( i );

    // 書き込み位置 ( put )を調べる
    int pos = out.tellp();


    // 文字列をかきこむ
    out.write( str, sizeof(str) );

    





___

■ IOStream.Lib

DESC 標準入出力の処理をするクラス stdio.h に相当する処理をしてくれる。 POINT cout std::ostream クラスのインスタンス cin std::istream の一例. cerr std::istream の一例. istream は STDIN から入力をうけつける. ( kb ではない. ) ostream は STDOUT へ出力する( Console ではない ) POINT printf() と違ってタイプセーフ。 書式指定の間違いも起きない。
    #include< iostream>
    using namespace std;

    // 任意の型に対して, 自動的にオーバーロードされたメソッドが呼ばれる。
    int i = 7;
    cout < <  i < <  endl;

    string s = "test";
    cout < <  s;

    double d = 0.1;
    cout < <  d < <  d;

    std::istream
      標準入力を担当する

    std::ostream
      標準出力を担当する
      C でいえば stdout に当たる


___

■ istringstream

文字列をつかってコンストラクをして任意の型に変換する。 atoi, atof の代わりに使う。
    #include< sstream> 

    using namespace std;

    istringstream iss( "10" );

    int i = 0;
    iss >> i;

    // エラーの検出をする
    iss.error();

    

___

■ C++ cast

DESC cast: 型変換をコンパイラに明示
    型変換
  int -> double
  double dval = (double)ival;
    型変更( 中身は不変 ? )
  long -> int *
  int *iptr = (int *)lval;
    const 外し
  const int ciptr;
  int *iptr = (int *)ciptr;

    cpp 
      -> cast の目的をコンパイラに明示
      static_cast: 暗黙の型変換があれば変換

  int -> long
  lval = static_cast< long>(ival); // OK
  void *-> int
  ival = static_cast< void *>ival; // ERR
reinterpret_cast : ptr 同士の変換 | ptr < -> int( ptr アドレスは不変 ) POINT 互換性のない ptr 同士のキャストが使いどころ
  int * -> long *
  lptr = reinterpret_cast< lptr>(iptr);
const_cast : const, volatile 外し cint * -> int * iptr = const_cast< int *>ciptr; cint -> int ival = const_cast< int>cival; // ERR( ptr 以外はだめ ? ) dynamic_cast : CBase から CDerived への型保障キャスト (逆)? POINT upcast : CDerived -> CBase downcast : CBase -> CDerived ( UML 参考 )
  CHuman -> CMan
  humanptr = dynamic_cast< CHuman *>manptr;
WARNING dynamic_cast が使用できるのは, 仮想メンバ関数をもつ場合
___

■ Destructor(デストラクタ)


  DESC
    デストラクタとはクラスのインスタンスが消滅する時点によばれるメソッド( 関数 )のこと
    普通はコンストラクタでした処理の後始末をする。

    コンストラクタは逆の順で実行される。
    ランタイムシステムが基底クラスのデストラクタもコールしてくれる。
    デストラクタ本体のコード --> メンバ変数のデストラクタ(宣言した変数の逆の順番) --> 基底クラスのデストラクタ
    class String {
      // コンストラクタで new をしたオブジェクトがあれば
      String() {
        m_data = new char[256];
      }

      // デストラクタで delete をする。
      ~String() {
        delete m_data;
      }
      
      
      char *m_data;
    };
コンストラクタと違い、1個しかもてない。
    class Test {
      ~Test();
    };
___

■ デストラクタのコールされるタイミング

デストラクタはオブジェクトが消滅する時にコールされる。 消滅するのは次のとき
     ローカルオブジェクトがブロックを抜けるとき。
     クラスのメンバオブジェクトは、そのクラスが消滅するときに一緒に
     一時オブジェクトはその式が終了したとき。
     動的に生成( new )されたオブジェクトは delete されるとき
___

■ デストラクタの自動生成

デストラクタを自分で定義しないとコンパイラが自動生成をする。 自動生成されるデストラクタは すべてのメンバのデストラクタを起動する。 コピーコンストラクタ も同様に定義しないとコンパイラが自動生成する。 REFERENCE CopyConstructor WARNING デストラクタを定義したら コピーコンストラクタも自前で定義をすること。 オブジェクトを参照するクラスの場合は多重に delete をすることになる。 つまりオブジェクトの所有権があいまいになるということ。
    {
      String s;

      // stmp::data は s::data と同じオブジェクトを指す
      {
        String stmp = s;
      }

      // s が消滅してデストラクタが起動すると data が2重に delete される。
    }  
POINT クラスがポインタをもち, リファレンス先を削除する義務がある( 所有者の )場合は コピーをする場合は オブジェクトを全体をコピーすること。( DeepCopy ) virtual にすると Instance の QUIT が call される. 明示的に delete を呼んだ場合, work の解放はされない /pro/test/virtualdtor/ POINT 派生クラスの Destructor が call されると 基底クラスの Destructor もコールされる Destructor が呼ばれるのは 2 とおりある System に call してもらう Stack Object delete 明示的に呼ぶ( 関数だから call しても問題なし ) d.~D();

class B2
{
 public:
  ~B2() { printf("B2::dtor dayo\n"); }
}; 
class D2 : public B2
{
 public:
  ~D2() { printf("D2::dtor\n"); }
}; 


void testDriveDtor()
{
  // 2 つ呼ばれる
  // D dtor
  // B dtor
  D d;

  // ~D() を呼べば 自動で 基底クラスの ~B() も呼ばれる
  d.~D();

  {
    //  ここも同じ
    D *d = new D();
    delete d;
  }
  
  // d はここで死ぬ
}

POINT delete bCls; とすると, bCls::dtor にアクセスすることになる. bCls が interface の場合は当然削除できない. WARNING virtual にしないと、その object の destructor しかコールされない
___

■ 仮想デストラクタ

仮想関数をもつクラスは基底クラスのデストラクタを仮想関数にする。 POINT より正確な条件は 基底クラスのポインタをつかって delete するならば、 そのクラスは 仮想デストラクタをもつ必要がある。
___

■ 仮想デストラクタ

この場合は Child のデストラクタが実行される。 Title のコンストラクタで実行した処理の解放処理がされない。
    Child *cld = new Title;
そこで デストラクタも仮想関数にしてあげる
    class Gui {

      virtual void draw();
      virtual ~Gui();       // 仮想デストラクタにする必要がある。
    };



    // 仮想関数のよびだしは 基底クラスのポインタ( 参照 )をつかってする。
    for each GuiList {
      gui->draw();  // virtual method
    }

    for each GuiList {
      delete gui;  // ここで各 GUI ( ボタン, スライダ, ウィンドウ )ごとのデストラクタが呼ばれる。
    }    
仮想デストラクタにしないと ~Gui() では基底クラスのデストラクタのみが実行されて、解放忘れがおきる。
    for each GuiList {
      // ~Gui() のみが実行されて派生先の開放処理がもれる
      delete gui; 
    }    
___

■ Alignment(境界配列)




  DESC
    データ型のサイズにより、2, 4, 8の倍数のアドレスに配置されること
    ハードウェア的な制約もあれば
    より高速な処理をするためにコンパイラ(リンカ、ローダ)が指示するものもある。

    メモリ、CPU 間でやりとりできるデータのサイズは 16bit, 32bit だったりする
    整列しておけば 4byte のデータを 1回で転送できる

  Alignment をする理由
     memory < -> CPU 間での data 転送が 4byte 単位のため整列した方が一度の転送ですむ
     最新のプロセッサの命令によっては 16 byte アラインメントにある必要がある。
     キャッシュラインにそろえることで、キャッシュミスを防ぐ。
POINT 変数は宣言順に確保されるとは限らない ローカル変数は宣言した順に, 配置されない 構造体の各メンバは宣言順だが, Alignment されて、メンバの間には隙間( padding ) が空く場合もある 構造体のサイズが padding されるのは, 各メンバが適切な位置に配置されるため隙間が空いてしまう。 隙間が空くのを防ぐにはメンバの構成を入れ替える。 または padding を明示しておく。
    BAD
    struct Foo {
      int    i0;
      short  s0;
      int    i1;   // int 型は 4 の倍数で配置されるため s0, i1 の間に隙間が空いてしまう。
      short  s1;
    };

    // OK
    struct Foo {
      int    i0;
      int    i1;
      short  s0;
      short  s1;
    };

    // OK
    struct Foo {
      int      i0;
      short    s0;
      char pad[2];
      int      i1;
      short    s1;
    };
Compiler の指定 で 変更可能( vc: 構造体 mem への alignment ) -> mem , cpu は 32 本の線で結合 -> 可変サイズで, Buffer をもつより, Alignment を守って大きめのサイズにした方が都合がよい場合もある.
    // sizeof(S) = 2
    //    2 コ で 4 byte
    struct S{
      short s;
    };

    // sizeof(C) = 1
    //    4 コ で 4 byte
    struct C{
      char c;
    };

    // sizeof(S3) = 6
    struct S3{
      short s0;
      short s1;
      short s2;
    };
x86 系では, double は 8ByteAlignment にすると効率がよい。 Architecture によっては必須になる. Alignemnt をそろえた, memory の取り方
     data = (void *)myMalloc( size + 32 );     // 32 byte Alignemnt

     s_data_org = data;                         // ori 保存

     data = (void*)(((u_int)data + 31) & ~31 ); // Alignemnt Macro
POINT struct cls mem 内が連続しているとは限らない 現実問題として, float, short, char, が struct 内に並ぶ場合は 連続して配置されている enum も連続していると考えられる // 12 byte struct Foo{ char c0; // 1 の倍数で alignment 1 float f0; // 4 の倍数で alignment char c1; // 1 の倍数で alignment };
                                    // 残り3byteを埋めないと次の構造体を配置した場合にf0の配置に問題がおきる。
    [c0][  ][  ][  ][f0][f0][f0][f0][c1][  ][  ][  ]
// sizeof(Foo) = 8 FILE: main.cpp struct Foo{ char c1; char c2; float f; };
___

■ プラグマでアラインメントを指定する

SYNTAX __declspec( align( # ) ) declarator コンパイラのプラグマでアラインメントを指定する。 VisualStudio では以下の方法で指定する。
    // Vector 構造体を 8 byte の境界の配置するように指示する
    __declspec( align(8) ) struct Vector
    {
      short x;
      short y;
      short z;
    };

    typedef struct ALIGN(8) { short vx, vy, vz, pad; } SHORT_VECTOR;
アラインメントを指定すると, アドレスが 8 byte の境界にあることがわかる。
    Vector v;

    int adr = (int)&v;
    adr %= 8;

    printf( "addr %d  %d", &v, adr );
POINT alignment の指定は 2 冪でないとだめ
    ERROR C2344: align(12) : アライメントは 2 の累乗でなければなりません。
    __declspec( align(12) ) struct SA
___

■ キャッシュライン(CacheLine)

よく使うデータはキャッシュラインに揃えることで、キャッシュミスが置きにくくなりプログラムの速度があがる。 cacheは、16bytesごとの塊xN個で構成されている。 この16bytesの塊1つを、1lineという。 lineが何個あるかは、cacheサイズをlineサイズで割れば計算できる。 1KB / 16 = 64なので、このcacheには64line存在する POINT 良く使うデータや、連続して使うデータが同じcache lineに割り当てられてしまうと、cache missが頻発してしまいます。
___

■ アラインメントを指定しない場合

Object はまず固有のサイズに対するアラインメントをもつ。 int は 4byte 境界に、 double は 8byte 境界に配置される。 int は 4 で割り切れる場所にないといけない。 クラス内にあるメンバオブジェクトは、オブジェクトのアラインメントのうち最小の値の位置にアラインメントされる。
    struct Test {
      char  c;
      short s;  // 2byte 境界にアラインメントするため, c と s 間に 1byte のパディングがはいる

    };



2. (push 8) は 1 の alignment の設定と比較してより小さい alignment が優先される 3. -> 適当に詰め物をする
  // 4 Byte 境界に押し込め と命令
  #pragma pack(push, 4) -> 12 byte
  struct Foo
  {
    char B;     // 1 byte alignment
    double W;   // 4 byte alignment( 8 より優先 )
    char H;     // 1 byte alignment
    short s;    // 2 byte alignment
  };

#pragma pack(pop) POINT プリミティブな値は、min( szObj, Alignment )の倍数のアドレスに配置する 一回で CPU に data を渡せるように箱に詰め物をするのが Alignment 構造体は 2冪サイズにするべき ( 最低でもキャッシュライン倍数にする )
___

■ 文字列(String)





  DESC
    c++ 標準ライブラリとして用意されている。
    C-String と比較して次のメリットがある

     安全性: 配列境界を超えない
     利便性: 標準C++ 演算子の使用が可能
     一貫性: 文字列という型を定義できる
   
    sizeof( string ) = 4;
    文字列を格納する際に, new, delete をしている

    string 型は クラステンプレート basic_string の実装のひとつ
    typedef basic_string< char, char_traits< char>, allocator< char> >    string;      
      // 空 string
      string();

      // C_String str を使用して生成
      string( const char *str );  
      
      // 他のstringを使用して string 生成
      string(const string &str);  


演算子 + string + string string + c_str c_str + string c_str + string
    // Compile ERROR にならないが "7" は追加されない
    string s;
    s += 7;
___

■ 結合

      string s;
      s += "a";
      s += "b";
      s += "c";

      //  "abc"
      printf( "%s", s.c_str() );

      s[1] = '\0';
      // "a"
      printf( "%s", s.c_str() );

___

■ 文字数

SYNTAX size_type size();
    // 3
    string s = "abc";
    s.size();
___

■ 参照

    // 参照
    char operator[](  idx );   
___

■ 検索

SYNTAX size_type find( const string &str, size // 検索する文字列 _type pos = 0 // 検索を開始するオフセット ); RET N : 見つかったインデックス位置 string::npos : 見つからない
    // 検索
    if ( s.find( "abc" ) != string::npos ) {

    }

    // 後ろから検索
    s.rfind( "abc" );

if ( string1 == string2 ){} string1 = string2; // string を代入 string1 = "foobar\n"; // C_string を代入 パスからファイル名をかえす。
    string filename( const string &path )
    {
      size_t i = path.find_last_of("/");
      string ret = path.substr(i+1, path.length());

      return ret;
    }

    string dirname( const string &path )
    {
      size_t i = path.find_last_of("/");
      string ret = path.substr(0, i);

      return ret;
    }
___

■ 部分文字列

substr SYNTAX basic_string substr(size_type pos = 0, size_type n = nr) const; DESC pos で指定した index から n 個の文字列を返す。 assign ( 部分列. ) str から、pos文字目から、n文字を取り出して設定 assign( const basic_string& str, size_type pos = 0, size_type n = npos );
___

■ 比較

compare ( 比較 ) // 文字列定数sのn文字までとの比較を行う。 int compare(const char* s, size_type pos, size_type n) const;
    string s = "foo bar g";

    // 3
    int nr = s.find(" "); 

    // 7
    int nr = s.rfind(" "); 
    
    // 0 番目から 3 個
    // foo
    s.substr( 0, 3 );

    // 見つからない場合は, -1 
    int nr = s.rfind("foo");

POINT string class はコンテナ ∴ 文字列の先頭、末尾を指す、begin(), end(), size() をサポート static にした場合は, Compiler 単位で作成されるので重複してしまう.
      // foo.h 重複しない.
  extern const char *strtbl[];
      // foo.cpp
      const char *strtbl[] = {
          "a",
          "b",
          "c",
        };
      // foo.h -> 重複する.
      static const char *strtbl[] = {
          "a",
          "b",
          "c",
        };
___

■ 参照(Reference)


    Reference とはオブジェクトの別名のこと。
    関数の引き数の参照渡しでよく使う。


       // 参照 渡し
       // const obj は変更不可
       //float func( float &foo )
  {  
    float foo = 0.0f;
  
    // bar は float 型としてうけとる( うけとることが可能 )
    // bar, foo は別モノ
  #if 0
    float bar = func( foo );
  #else
    // foo の別名となる
    float &bar = func( foo );
  #endif  
    bar ++;

    printf( "foo[ %f ]\n", foo );
    return 0;
  }
引数渡し、返り値、共に普通に渡せばOK
    {
      int &foo( int &b ){
      static int a;
      return a;
      }
    }
    
    int c = 77;
    int &d = foo( c );  // 普通に渡す && 普通に受け取る
    d = 12; // a = 12 になる    

    int d = foo( c );   // 参照としてうけとらない場合は、int 型を返しことと同一
    d = 12 // a = 0 のまま
  POINT
    private 変数 を参照返しすることで、get, set 相当のことをする

      private:
  int x;
      public:
  int &getX()( return x; )

  WARNING 
    ローカル変数の参照を返してはいけない ( ∵ 参照先は消滅 )

    STL vector< int> arr[i] はローカル変数なので、参照として返してはいけない

  std::vector< int> arr
  return arr[i];  // ERROR;

    参照変数 は定義する際に、初期化が必要( ∵ 変数の別名, compiler の立場で考えれば自明 )

    ERROR
    int &foo;
    int a;
    foo = a;
    
    OK
    int a;
    int &foo = a;

  // 参照 の考察  
    {
    int b = 7;
    int c = 10;

    int &a = b;   // b は a ともいう
    a = c;        // a に代入 == b に代入
    
    cout < <  b;     // RET 10
  }
// cls の member で reference がある場合は, 初期化list でおこなうこと
___

■ リファレンスの初期化

リファレンスを作成する場合はリファレンス先への参照が必須になる。
      ref の初期化時点 ( 逆に初期化が必須 )

      // BAD
      int &k;
      // OK
      int &j = i;

___

■ リファレンスとポインタの違い

POINT ポインタを定義するとポインタ型の別オブジェクトができる。 リファレンスは既存のオブジェクトの別名なので新規のオブジェクトはできない。
___

■ リファレンスを返す

リファレンスを返すことで、関数コールは左辺値となる。
      class Array
      {
        public:
         float &operator[] ( unsigned int i ) throw( outOfRange );
        private
         float data[100];
      };

      arr::operator[]( unsigned int i )throw( outOfRange )
      {
          if ( i>=100 ){
            throw outOfRange("array idx is out of range");
          }
          return data[i];
      }

      {
        Array a;

        // 左辺値に値 7 を代入する
        a[10]= 7;       // obj::data を変えることを意味
      }
___

■ 仮想関数



___

■ 仮想関数でフレームワークをつくる

SAMPLE シンプルウィンドウ サンプル フレームワークをつくる場合は先に制御フローをつくってしまい アプリケーション固有の処理を仮想関数をつかってハンドラとして用意してしまう。 OpenGL のフレームワークをつくる。 不変な部分をシステム( フレームワーク )側で用意する。 そして可変な部分を 仮想関数 にしてアプリケーションごとにカスタマイズさせてあげる。
    class GLFramework {
      public:

      // アプリケーション固有の処理の仮想関数として用意しておく。
      virtual void onRender();

      // 固定の内容は仮想関数にしない
      void run();

    };

アプリケーションは Framework の流れに沿って必要な部分( カスタマイズ )したい部分を 上書き( オーバーライド )する。
    class Sample : public GLFramework {
      public:
      // 赤くかく
       void onRender() {
         glClearColor( 1, 0, 0, 1 );
         glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
       }
    };

    class Sample2 : public GLFramework {
      public:
      // 青くかく
       void onRender() {
         glClearColor( 0, 0, 1, 1 );
         glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
       }
    };
後は実行するだけ。全体の流れはフレームワークにまかせる。
    #include "glframework.h" 
    int main() {

      {
        Sample1 app;
        app.run();
      }
      {
        Sample2 app;
        app.run();
      }
      return 0;
    }
フレームワーク側は共通に必要となる処理を用意しておく。 ウィンドウをつくったり, メッセージループを回す部分は共通の処理なのでしておく。 不変な部分にあわせてシステムをつくる。
    GLFramework::GLFramework {

      // ウィンドウをつくる
      m_hWnd = CreateWindow();

      
    }
    
    メッセージループを回す
    void GLFramework::run() {

      while ( PeekMessage() ) {

        // 仮想関数をよんであげる。これでアプリケーション固有の処理がよばれる。
        onRender();
      } 
    }


___

■ virtual 関数の使いどころ

具体的な処理を派生クラスにまかせるときに使用する。 基本クラスで宣言され、派生クラスで再定義されるメンバ関数 仮想関数の再定義において、prototype が同一のものをoverride : 異なるものを overload POINT 共通部分を探ることが重要 その部分を virtual 関数にする。 拡張が想定される位置を仮想関数にする。 仮想関数にすることで、関数テーブル経由でメソッドを動的にコールすることができるため 可変になるということ。 カスタマイズ可能という意味。 基底クラス側でハンドラとして用意しておき、実際に利用する側( 派生クラス側 )が具体的な処理をかく。
    class Converter {
        void output( const string &path );
    }
POINT 関数ポインタでも同様のことができる
  Application::display(){
    virtual void Task::main();  // 具体的な処理は派生先にまかせる。
  }
広範囲の集合に対して処理をする際に有効 DESC virtual は呼ばないと カスタマイズされているかわからない virtual とは [ 同様にみなせる ] オブジェクトであることを保障する方法 型の継承の意味 POINT virtual void save(); -> カスタマイズ可能 save() メソッド
  //  virtual は呼び出す側の再利用を意味する
  for( i=0; i< 10; i++ ){
    item->save();   // 固有のサービスがコールされる
  }
___

■ InterfaceClass

DESC interface class を使用することの目的は 共通の規格( ふるまい )を強制すること。 フレームワーク( 呼ぶ )側の再利用が促進される。
___

■ 抽象クラス

DESC 純粋仮想関数 をもつクラス POINT [ 純粋仮想関数だけ ]が定義されているクラスはインターフェースという 純粋仮想関数 を含む class を抽象クラス ( abstract class )と呼ぶ abstract class は生成できない。しかし pointer は OK POINT 継承されることを前提としたクラス( デザインパターン的視点 ) 純粋仮想関数を含むクラス( 文法的視点 ) POINT クラスが派生されてからしか決定できないようなデータを使うときに抽象クラスを使用 POINT 抽象基底クラスの意味( 設計的 ) DESC 純粋仮想関数により、フレームワークの提供側としては default の振る舞い 仮想関数の[ 強制的な使用 ]を示すことになる
      Task->Run();

      Window->Display();
___

■ vtable( 仮想関数 table )

DESC cpp コンパイラが自動で method 第一引数に this ptr をいれていくれる POINT vtable とは FunctionPointer Table のこと Class ごとの情報のひとつ Debuger でみると __classType という名前がみれる オブジェクトのディスパッチテーブルはオブジェクトの 動的にバインドされるメソッドのアドレスを保持する。 コンパイラが virtual 宣言を見つけると、テーブルを作成する。 Method の Call は アドレスをオブジェクトのディスパッチテーブルからとって利用する ディスパッチテーブルは同じクラスに属するオブジェクトでは全て同じ 通常オブジェクトから共有される。 互換性のある型のオブジェクトは同じレイアウトのディスパッチテーブルを持ち メソッドのアドレスは 全ての型互換のクラスの中で常に同じオフセットに現れる。 メソッドのアドレスをディスパッチテーブルから取り出すことで オブジェクトの実際のクラスに対応したメソッドが得られる。 各クラスのインスタンスは関数テーブルへのポインタをもつことになる。 そのため仮想関数をもたないクラスよりポインタのサイズ分が増える。
    class Job () {
      int i;

      public:
        virtual void run(){}
    };

    // 8
    Job j;
    printf( "size %d" sizeof( j ) );
1. static const char *item[] = { "run", "title", "menu", "reset", "exit", }; for ( int i=0 ; i < sizeof(item)/sizeof(item[0]) ; i++ ) { 2. // 次の2項目を相手に渡す // 渡し方としては // 1. ReqAdd の ptr を渡す。 // 2. メンバ関数で id, str を渡す. こちらの方がスマート // // スマートでない方法は data[] = { data0, data1, data2 ... } サイズの計算がメンドイ // tgt->sendSignal( sig, data ); // // 送るべき内容を message Class としてまとめてしまう。 // // 各 message はそのサービスをするクラスが内包すれば OK // 1. code での マクロの反映方法( rebuild は必要 ) #if defined(_WIN32) vsprintf(d.top, form, arg); #else vsnprintf(d.top, LINE_SIZE, form, arg); #endif
___

■ 関数のオーバーライド

DESC sub cls で base cls の関数を overwrite しないならば、base cls のものが使用される sub cls で宣言した 仮想関数は, 実装しないとコンパイラに怒られる。 POINT ABC の実装はすべての派生先で必要か ? 一度でも 実装すれば、後の派生先は実装しなくても OK virtual static を併用可能か ? DESC できない( ERR: virtual メンバ関数は静的メンバ関数にはなれません )
___

■ オーバーロード

関数のオーバーロードとは同一スコープで同じ名前をもつが signature が異なる関数こと。
    class Test {

      void func( int );
      void func( float );

    };
POINT signature とは次の構成のこと
    関数名 ( パラメータ型と順序 )  const, volatile の有無
以下は異なる signature
      void func( int ) const ;
      void func( int );
オーバーライドは異なるスコープで同一の signature をもつこと。 派生クラスで仮想関数テーブルを上書きしてしまうこと。
    class Base {
      virtual  void func();
    };

    class Derive : public Base {
      void func();
    };
___

■ クラス継承間での同名の関数

派生クラスと基底クラスで同名の関数があると、内部スコープの名前が外部スコープの名前をかくす。 そのため、このような状態にならないような名前をつけることが大切。
    class Base {
      void func( int );
    };

    class Derive : public Base {
      // 同じ名前
      void func( float );
    };

    Derive d;

    // Derive::func( float )が呼ばれる
    //  派生先の名前 ( func )が基底クラスの名前を隠してしまうということ
    d.func( 10 )
POINT 1個のクラスはひとつのスコープになる。
___

■ 仮想関数のコンストラクタの呼び出し

コンストラクタ内で仮想関数を呼ぶとそのクラスのメソッドが呼ばれる。 もし派生先のメソッドが呼ばれると 派生のメンバを操作することになるためこの動作は正しい。
    class Derive : public Base {
      void func();
    };

    Base::Base {
      // これは Base::func() が呼ばれる。
      func();
    }
___

■ 仮想コンストラクタ

WARNING コンストラクタは仮想関数にできない。 理由は 基底クラスのコンストラクタがコールされている時点では 派生クラスのメンバが初期化されていないから。
___

■ スコープ演算子をつかう

仮想関数内で、スコープ演算子をつかうことでクラスのメソッドを明示できる。 仮想関数テーブルを経由せずに( パイパスして )明示的に呼ぶときに使う。
    class Gui {
      virtual void move() {}
    };


    void Button::move() {
      // 基底クラスの move() を再利用する
      Gui::move();

      // Button 固有の move() 処理をかく
    }

クラスの利用者はこの機能を通常はつかわない。 クラスの開発者が、派生クラスのメソッド、コンストラクタ、デストラクタ内で便宜上つかう。
___

■ 純粋仮想関数(PureVirtualFunction)

WARNING 抽象基底クラスは デストラクタの "定義" をもつ必要がある。 リンカーが派生クラスのデストラクタから呼ばれる Base::~Base() を探すため。
    class Base {
      public:
        virtual ~Base() = 0;
    };
    
    class Derive : public Base {
    };

    int main() {
      Derive d;
      return 0;
    }
定義すればリンクエラーにならない。
    Base::~Base(){}
派生クラスをインスタンス化するには、純粋仮想関数のすべてを実装する必要がある。 このときに、継承元をたどって実装されていればいい。 要は仮想関数テーブルが埋まっていればいいということ。
    class Base {
      public:
        virtual void f() = 0;
        virtual void g() = 0;
    };

    class Derive1 : public Base {
      void f();
    };

    class Derive2 : public Derive1 {
      void g();
    };
___

■ 非インライン関数

仮想関数をもつクラスはひとつの 非インラインメソッドをもつべき。
    class Base {
      public:
        virtual ~Base();
    };
    
    class Derive : public Base {
    };

    int main() {
      return 0;
    }
___

■ cast(キャスト)



    型変換
  // int -> double
  double dval = (double)ival;

  // 
  long -> int *
  int *iptr = (int *)lval;

  
      reinterpret_cast : ptr 同士の変換 | ptr < -> int( ptr アドレスは不変 )
           

___

■ reinterpret_cast

互換性のないポインタ同士のキャストに利用する。 reinterpret_cast は偽者の型でもキャストできてしまう。 安全性という視点では使うのは良くない。
    // int * -> long *
    lptr = reinterpret_cast< lptr>( iptr );
dynamic_cast : CBase から CDerived への型保障キャスト (逆)? POINT upcast : CDerived -> CBase downcast : CBase -> CDerived POINT cpp スタイルのキャストを利用することで, キャストの意図を明確にする WARNING キャストは 飽くまで [ 型がこうである ] と コンパイラに言い聞かせるだけ。 ( 保障は一切ない ) だから Cast は最低限にするべき ( C++ ならば Template で代用すること )
    void onClick( Gui *gui ) {
      
      Button *b = reinterpret_cast<  Button >( gui );
    }
POINT アセンブラでは型という概念がない アドレスを指定して, Data を Add, するだけ 中身( アドレスの指す先の bit 列 が Integer )を意味するかどうかは プログラマが責任ををもってしていた しかしそれば手間で、中身を間違うという事故があったため、型というルールができた。
    // キャストの内容によってメモリ上の値が変わることも、不変な場合もある
    // VisualStudio のメモリウィンドウで確認できる。

    int i = 128;   // MEM IMG [ 0x 80 00 00 00 ]
    int i2 = i;    // MEM IMG [ 0x 80 00 00 00 ]
    float f = i;   // MEM IMG [ 0x 00 00 00 43 ]  // ここが43となる点に注意
結論 アドレス( という数値 )を格納する場合は, 変更されない. なぜなら adr の指す先の Object をこう読んでね とい言うようなもの. 数値型の場合は, 型によって表現方法が異なるので, bit 列が変更される. base obj を derive obj の ptr に cast して操作すれば,問題があることを意識する
___

■ const_cast

const, volatile 外し
  // cint * -> int *
  iptr = const_cast< int *>ciptr;
  // cint -> int 
  ival = const_cast< int>cival; // ERR( ptr 以外はだめ ? )
___

■ static_cast

DESC [ 暗黙の型変換 ]がある場合のみ変換できる。 [ 安全な型変換 ] 暗黙の型変換があれば変換 安全な cast を意味するので, c_style_cast より積極的に利用するべき OK
    // void * < -> any *  
         -> down cast の場合, 派生先の領域にアクセスするのは危険かも

    // upcast
    Bcls *p = static_cast< Bcls *>( pDcls );

    // const をつける
    int p = 10;
    const int cp = static_cast<  const int >( p );
    cp = 20;  // error: assignment of read-only variable `cp'

      static_cast: 

  int -> long
  lval = static_cast< long>(ival); // OK
  void *-> int
  ival = static_cast< void *>ival; // ERROR


ERROR Foo *p = static_cast< Foo *>( pBar ); // 継承関係のない cls 3. dynamic_cast ptr が指す obj の型を取得( obj がどの mem func を support しているか確認という意味 ) WARNING polymorphic cls のみ( ∵ vtbl 必要 ) 4. reinterpret_cast 指定された型に[ 読み替える ]のみ -> 無理やり別の型に変換する.
      void *p = reinterpret_cast< void *>( &fooObj );  // ptr ads は不変
WARNING 多重継承していると 問題が起きる POINT
    // コンパイルエラーで出力される内容が正しい型変換を意味する
  MSG:: c style cast || static_cast が必要です
___

■ dynamic_cast

POINT オブジェクトがあるインターフェイスをサポートするか調べるときに使う。 派生クラスから基底クラスへダウンキャストする時に使う。 [ ptr がさす obj の型を取得 ] として考えれば OK dynamic_cast が使用できるのは, 仮想メンバ関数をもつ場合
    Base *p = new Derive();

    
    Derive *d = dynamic_cast< Derive *>(p);


    Another *p = new Another();

    // キャストできない場合は NULL を返す
    Derive *d = dynamic_cast< Derive *>(p);
DESC base -> derive ptr への cast constructor 時に dynamic_cast< derive *>(this) としても 変換は不可能 construct 時に 処理をわけることは不可能 WARNING class が virtual 関数を含む必要あり == polymorphic class の必要あり( compile err )
___

■ 演算子のオーバーロード


    関数の overload と同様に 演算子 を overload( 拡張 )する仕組み
    C++ では 同一の関数名でも, 引数が違えば 定義できる
    ただし 返値 のみが異なる場合は無理かも
    ( gcc では可能 )

  POINT
    使いどころは、よく使う関数を短い記述で書くときに使う。
    表記は演算子だが、関数がコールされる。( 表現の問題 )

    vec3 x, y, z;
    z = x.add( y );
    
    // 演算子をオーバーロードすると簡単かつ直感的にかける
    z = x + y;

    vec3::operator +( const vec3 &rhs )
    vec3::add( const vec3 &rhs )
WARNING: operator->() は禁止. class T{ public: T* operator->(){ return this; } int Fuga(){ return 4; } }; // 中略 void main() { Hoge hoge; // この定義と矛盾して見える. printf("%d\n", hoge->Fuga() ); // 4 hoge の定義と離れていたら悪夢 } WARNING // operator=() は ちょうど 1 ARG が必要
     void operator=( int i );
operator= の signature は 現在 2 つある. ( 組み込み型と同様にふるまうようにするには, 自身の参照をかえす. )
   Cls &operator=( const Cls &);

      次は operator=() が call されない. なぜかわかる.  ? 
      
      {
    Foo f1;

    // CopyCtor が走るらしい. ( CMP /Od にしても発生. -> 要は CopyCtor と同じ意味. ? )
    Foo f2 = f1;    // Call されない. 

    // OK
    Foo f2;
    f2 = f1;
      }
POINT Foo f = 10; -> f(10); に変換される -> Foo( int ) がないと cmp におこられる. -> メタファーとしては, char *str[] = {"aa", "bb", "cc" }; 1 引数のみは Foo = 10; のような記述できる 引数をひとつだけとる ctor のことを,“変換コンストラクタ(converting constructor)”という POINT left operand は暗黙として this pointer で渡される WARNING 演算子が受け取る param list 数の変更は不可
    +  : nr = 2
    ++ : nr = 1
POINT 通常の演算子と同様に動作することを保障すべき
  class integer{
    int val;
    
  public :
    int operator +( integer obj ){
      return this->val + obj.val;
    }
  }
___

■ operator++

class point{
public :
  int x, y;
  void operator ++( int n ){    // 後置を表現する prototype
    x++; y++;
  }
  point operator ++(){      // 前置
    x++; y++;
    return *this;
  }
}
POINT default 後置 increment は値を返却 -> increment
    int val = 3;
    int foo =  val++; // foo = 3;

  point o1, o2;
  o2 = ++o1;
  o2++;
___

■ operator[]

添え字演算子
    class array{
      int arr[2];
    public
      int & operator []( int n ){
        return arr[ n ];        // これで参照を返すことになる ? 
      }
    }
___

■ operator()

SYNTAX void operator()() DESC Functor と言われるクラスがもつメソッド 関数のフリをしたクラスに使う。
    class Foo
    {
     public:
      void operator()() { 
          printf("fucntor\n");
      }
    }; 

    {
      Foo f;
      f();
    }
___

■ operator=.代入演算子

member 変数をすべてコピーする。 コンパイラが自動生成。
___

■ operator< <

DESC operator< < (a, b) == a< < b
    ostream& operator< <  (ostream& o, const fraction &n ) throw()
    {
      return o < <  n.nr < <  "/" < <  n.denom;
    }
___

■ operator ++

SYNTAX T& operator++() DESC 前置インクリメント演算子 この式は先にインクリメントする前の値を返すこと。

    class Number {
      Number & operator++() {  
        m_i ++;
        return m_i;
      }

      int m_i;
    };
    


___

■ operator ++(int)

SYNTAX T operator++(int) DESC 後置インクリメント演算子 この式はインクリメントした後の値を返すこと。

    class Number {
      Number operator++(int) {  
      // ここでコピーコンストラクタが発生する
        Number old = *this;
        m_i ++;
        return old;
      }

      int m_i;
    };

___

■ OperatorNew


    new 演算子の処理は自前で定義することでカスタマイズできる。



___

■ perator newをオーバーライドする

メモリを確保する処理をオーバーライドする。
    void *operator new( size_t sz ) {
      gCnt ++;
      return malloc( sz );
    }

POINT ペアになるように operator delete も定義する。
    void operator delete( void *p ) {
      gCnt --;
      free( p );
    }

___

■ 追加の情報をわたす

operator new() は引数に応じたものが呼ばれる。 最初の size_t 引数は必須の項目。その後は任意。 デバッグ情報をうけとる operator new では 2つの引数を追加する。
    operator new( size_t sz, const char *file, int line ) {

    }
    int *a = new( __FILE__, __LINE__ ) int[4];
メンドイのでマクロにする。
    #define NEW  new( __FILE__, __LINE__  )

    int *a = NEW int[4];
___

■ mallocする領域に追加する

確保するメモリの前後にマークをつけることでメモリ破壊を検地する。
    void *operator new( size_t worksz ) {
      int sz = worksz + sizeof( int ) * 4;

      char *p = (char *)malloc( sz );

      int *pt = (int *)p;

      pt[0] = worksz;
      pt[1] = 12345678;
      
      pt = p + sizeof( int ) * 2 + worksz;
      pt[0] = 12345678;
      
      return p + sizeof(int)*2;
    }    

___

■ malloc.のように失敗しても NULL を返さない


    //  これは OK
    void *p = malloc( 1024*1024*1024 );
    if ( p == 0 ) {
      printf("malloc fail\n");
    }

    // new は失敗すると Exception をなげる
    class Test{
      int i;
    };

    try {
      Test *p = new Test[350*1000*1000];
    }
    // ここで補足しないと 
    catch(...){
      printf("fail new\n");
    }        
// NULL を返したいなら new(std::nothrow) を利用する // 過去の互換性をとるための new
  int *p = new( std::nothrow ) int[350*1000*1000];
  
  if ( p == NULL ) {
    printf( "new fail" );
  }
// WARNING // Exception を投げないのは Memory 確保のときだけ // その後の ctor で投げられたら OUT


    class Test
    {
      int i;
     public:
      Test(){
        printf("Test ctor\n");
        throw( bad_alloc() );
      }
    }; 


    // Memory 確保に失敗すると NULL をかえす
    //  成功すると ctor をよぶ -> ここで Exception を投げられる可能性はある
    Test *p = new( std::nothrow ) Test[1*1000*1000];

    if ( p == NULL ) {
      printf("new fail\n");
    } 


___

■ 宣言しなくてもメンバ関数はstatic扱い

DESC メモリブロックの指定は外からする必要あり
    void *operator new( size_t t ) {
      // `this' is unavailable for static member functions

      // MemBlk を取得する関数に this はない
      dpi( this->data );

      // この後に constructor が実行される。
      return work;
    }
POINT static な GlobalNew は FileScope で利用される -> ! WARNING がでる. ! LocalDelete() を定義しても, dtor は呼ばれるらしい [ System ] -> Cls::dtor() -> Cls::operator delete(); という順番らしい. operator delete() はあくまで, Memory の解放のためにあるようだ. class Foo { public: ~Foo(){ dps("Foo dtor"); } // うばう. dtor は走る. void operator delete( void*p ){ printf("operator delete"); } }; WARNING: WARNING C4211: 非標準の拡張機能が使用されています : EXtern が static に再定義されました。 POINT 優先順 Global < FileScopeGlobal < ClassLocal の operator new 実は, new, delete は Memory を確保に失敗すると Exception を投げる EXception を投げる際も, new, delete が呼ばれる どこから new, delete をどこから利用しているかわからない. だから Exception を投げずに, NULL を返す仕様の方がよいかも Constuctor は new XXX の形でしか呼べない. ? size_t 以外の OperatorNew ( PlacementNew ) を利用した場合は, Overload になるのかな ? -> 隠ぺいされてしまう -> 隠蔽されない. ! Build できてしまう. WARNING C4345: 動作変更 : 形式 () の初期化子で構築される POD 型のオブジェクトは [ 既定初期化 ] されます この WARNING の考察. 次の条件の際におきる. DefaultCtor 未定義. && Foo() // () ありの ctor ( -> 0 初期化. ) && PlacementNew の定義. () なしならば, 0 初期化されない. SOL ctor で () をつけない. ( 2 種類ある ) 要は PlacementNew ないで, Object を初期化しても DefaultCtor で 0 Clear しますよ ! と言っている POINT PlacementNew をする場合は, ctor をしっかり定義すること STL は Cpp の CMP に必ず付属する. ( だから PS3 でもある. ) -> STL の Allocator 指定は, 要は, Memory をここからとってよ ! という意味. 自分の中で, new する場合は, 別途の領域から取得する. 実は operator new は Method なので, OverWrite, OverLoad が可能. -> public に Access されるので, public にする必要がある. Class 内で宣言したものは, 要は, Object の生成空間を指定する際に使う. -> さらに継承されるので, 継承によって, Pool を指定することもできる. // Memory を指定するための クラスを用意してもいい. // 継承すれば, OK ! ( MultiInheritance ) // // MemorySelect を利用したもの同士を継承してしまうと競合がおきる. // class MemorySelect { }; 派生先で定義した場合は, OverWrite される. -> しない場合は, bCls で[ 定義したもの.ま.で ]さかのぼる. operator new( size_t , ... ) 引数リスト自体を カスタムすること可能 -> 逆に呼び出したい new の Signature にあうように指定する必要あり. ClassLocalNew を定義した場合は, new Foo; では GlobalNew は見に行かない. -> このあたりは Scope の解決の問題かも.
    operator new ( size_t sz, void *memBlk ) {
        ...
    }
    new( gWork ) Array();
Class の外で定義したものは, Global( 誰からも見れる )New, GlobalDelete となり, new , delete 時に call される. -> operator new も operator の考えに基づけば, 関数のひとつ. さらに system の new も malloc() を呼ぶらしい. ? -> ので自分で NewGbl を overwrite する場合も, malloc 利用して OK C:\Program Files\Microsoft Visual Studio 8\VC\crt\src\new.cpp void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc) { // try to allocate size bytes void *p; // malloc() している. while ( (p = malloc(size)) == 0 ) if (_callnewh(size) == 0) { // report no memory static const std::bad_alloc nomem; _RAISE(nomem); } return (p); }
___

■ 初期化リストは必ず記述

WARNING 仮引数は _data とする
      foo()::foo(int _data) 
      : data(_data)
___

■ Explicit


  DESC
    変換コンストラクタに利用しないようにコンパイラに知らせる。
    変換 Constructor が起動して ClassA( 111 ); となり 一時 ATmp ができる. 
    operator = () がはしる.   
     
  POINT
    Copy する必要がある場合は, 明示的に定義する. 
    不要ならば, 禁止する


   class T
   {
    public:
      explicit T(int arg);
   };

   void main() {
      T a( 10 );
      T b = 10;   // ERR [10]  ---> aTmp[A(10)] ---> b = aTmp; を禁止する. 
   }

___

■ メンバー関数ポインタ

  


    次のように展開するとわかりやすい

    メンバ関数は通常の C スタイルの関数とはシグネーチャが異なる。
    暗黙の this ポインタをもつ。


       func : Foo::memberFunc() を指す Ptr なので, Foo に func() という FuncMem がなくても OK.
       object->*func() === object->(*func)() === object->memberFunc()

    C3837 :
       FuncMem の アドレスを渡す場合は, &Foo::func; と明示する必要あり.

    class Foo
    {
      public:
        void func();
    };
POINT クラスのメンバ関数の型を typedef する。 関数ポインタ型の構文はわかりずらいので typedef で別名をつけると便利。 コンパイラに void T::( void ); 型を FuncPtr であると教える。
      #typedef void ( T::*FuncPtr)();
      {
      // p はメンバ関数を指すためのポインタ変数。
       FuncPtr p;

        // メンバ関数ポインタにメンバ関数をセットする
       p = T::func();     
       p = &T::func();     

      
       // コールするときは this に渡すインスタンスからよびだす。
       class obj;
       (obj.*p)();         

WARNING C スタイルの関数ポインタを必要とする場所で、 メンバ関数ポインタを渡すことはできない。 この場合は , 静的メンバ関数、または非メンバ関数を利用する。 シグナルハンドラ

    #include< signal.h> 

    int main() {
      // 静的メンバメソッドならば渡すことができる
      signal( SIGINT, Test::signalHandler );
    }

    // グローバル変数経由でわたす インスタンスを取得して メンバ関数をよびだす


スタティックメンバ関数ならば 呼び出し規約は同じになるので C スタイルの関数ポインタと互換性がある。
___

■ ステートパターン内で利用する

POINT 動作を表す変数( 動作もまた情報 ) -> ex. stateFunc ( 動作名をいれよう ) -> 応用例( FSM ) class obj { protected: // 状態別 mem 関数の宣言: typedef void (obj::*stateFunc)(); // objCls の funcPtr( 内部的には obj_stateFunc() ) // それを保持する変数 stateFunc statFn; private: // 状態別関数 void state1() { printf("do state1\n"); this->statFn = state2; } void state2() { printf("do state2\n"); this->statFn = state1; // cls 名を指定しなくても OK } public: Obj(){ stateFunc() = state1; } // update 処理では状態関数を呼ぶだけ inline void update(){ (this->*statFn)(); } }; { switch ( state ){ case STATE1: state1(); break; case STATE2: state2(); break; } } typedef void (T_Class::*SetParamProc)( const T_Param &val ); typedef const T_Param &(T_Class::*GetParamProc)(); // メンバ関数ポインタ を用いた todo 処理の例 class TestCls { /* TestCls の関数か, global関数かを cmp に通知 */ typedef void (TestCls::*Func)(); public: // todo 一覧 void foo(){ printf("foo") }; void bar(){ printf("bar") }; TestCls(){ /* TestCls の foo() を渡すことを通知. ( & は任意 ) */ todoList.push_back( &TestCls::goo ); } vector< Func > todoList; void action(){ int i; for( i=0; i< todoList.size(); i++ ){ Func p = todoList[i]; /* 呼ぶときは, どの inst かを通知 */ (this->*p)(); } }; }; DESC 通常 typedef void (*func)(); cls typedef void (clsName::*func)(); // void clsName::func() 型の funcPtr 関数 ptr の ads を渡すには ... 通常 void foo(){ ... } func a = foo; cls typedef void (clsName::*func)(); // void clsName::func() 型の funcPtr void clsName::bbb(){ ... } 関数 ptr を param とする function は // template cls にすると, 関数の型を以下のように可変にできる void setClassInfo( T_Class &inst, SetParamProc set, GetParamProc get, std::string _name = "" ); template< class T_Class, class T_Param> // この cls の この param という class Test : public TestValue< T_Param> { private: }; // 渡し方 // & をつける POINT template化 cls は cls 生成の時点で template 指定するが、 mem 関数 は 通常とおり使用できる. 関数ポインタに格納する関数は, [ class 名 ]も同一でなくてはならない。 派生先の関数でも格納は不可能( 派生先しかない情報にアクセスされたらOUT ) この場合は, virtual bcls::todoXXX(){} として枠組みをつくって, 派生先で 必要な処理を overwrite することで OK もしくは, 各クラスで todo 処理をするふるまい [ actionTodo() ] を作成する template ということは, class 名の部分を置換してやれば可能。
___

■ SYNTAX


___

■ type

___

■ bool

DESC C++ の組み込み型 true, false : 予約語 ( 真偽の実装は未検証 )
___

■ include

新しいC++ header はファイル名を指定せずに、標準識別子のみを指定。   コンパイラによって、ファイル名にmappingする。(こうすることで、本当に必要な定義、prototype が   include される。つまりコンパイラ自身責任をもって選択する。 )
   #include< iostream>
___

■ new


  DESC
    new で確保する際の メモリサイズ は new TYPE で決まる
    new は Constructor をコールする

___

■ new new[] delete delete[] を間違えないこと

~QUIT{ printf"quit"; } とすれば, 1度しか call されない.
      int main( void )
      {
        Foo *p = new Foo[8];
        for( unsigned int i=0; i< 8; i++ ){  p[i].srv();  } 
        delete p;  // gcc では core dump 
        return 0;
      }
new[] の際に mem blk に 要素数を埋め込む. new -> [memtag][mem...] 0x01000000 new[] -> [memtag][pad][要素数][mem...] 0x01000010 -> memtag を取得してみる. MEMTAG *ptag = static_cast< MEMTAG *>(p) - 1;
___

■ newをカスタマイズする(placement new)

new は operator new() をオーバーロードすることでカスタマイズできる。 カスタマイズする目的はメモリのアロケートを独自の方式にすること。 new の後に () にパラメータを与えることで、アロケータにパラメータを渡すことになる。 あらかじめ用意したメモリ領域(メモリプール )からアロケートする。 最初に大きめのサイズをまとめて確保して、切り出して使うのがおおまかな流れになる。
    // 最初にまとめてメモリ領域を確保
    static char memPool[ 1024 ];

    void *operator new( size_t sz, char *buf ) {
      return sBuf;
    }  

    {
      Test *p = new( memPool ) Test();
    }
WARNING 返すアドレスは以下の条件を満たす必要がある。
     要求されたサイズ ( sz )よりも大きい。
     適切にアランメントされたアドレスになっている。
        ( クラスのメンバに double を含む可能性があるなら 8で割り切れるアドレスを返す必要がある )
POINT new を overwride する場合は, 対応する delete も overwride するケースが多い. Pool からとった場合は, 自分で解放する. Component したクラスが OperatorNew を定義していても OverwriteNew は呼ばれない Component したクラス自身を new した際にくる.
    class Bar {
      Foo f;
    }  
    Bar *b = new Bar();  // f の生成は Bar の生成場所で INIT される. 
メモリリークを防ぐには以下のカスタマイズバージョンを使う。
   #if _DEBUG
   #  define NEW new( __FILE__, __LINE__ )
   #else
   #  define NEW new 
   #endif
WARNING クラス内で new/delete を定義する場合は, NEW の定義を変えることでコンパイルできなくなる 同様に delete もカスタマイズできる。 独自にアロケートしたメモリを解放する処理をかいておく。
    void operator delete( void *ptr ) {
      ...
      // 
    }
___

■ new で realloc できるか ?

DESC できない POINT new を使う理由はコンストラクタをコールしてくれること
___

■ global new

DESC class 単位ではない new class 単位が Local WARNING STL などはデフォルトで GlobalNew を利用している可能がある.
___

■ ファイナルクラス


    C++ では言語構文として final 指定ができない。
    そのためコンパイラレベルではチェックができない。
    コメントとして残すことしかできない。

    ファイナルメンバ関数の場合は :: によって、仮想関数テーブルをパスできる。

    class Derive : public Base {
      public:
        /* final */ void func();
        void f();
    };

    void f() {
      // これはこれ以上オーバーライドされないので
      ::func();
    }

___

■ RTTI(RunTimeTypeIdentification)


    RTTI とは動的型チェックのこと。
    実行時に型が正しいかチェックすること。
    

    コンパイラが自動生成するクラスのメタ情報のこと( クラスの型情報を埋め込む )
    実行時に型情報を取得できる機能

    RTTI を使うと、オブジェクトの型情報を調べて、安全にダウンキャストできる。

    
      
  USAGE
    plm cls 作成
  2. /GR   ( VC )
  3. pDerive = dynamic_cast< derive *>( pBase );

    手動でするならば, 次をクラスに持たせる
    要はどの種類かわかればいい
    clsID
    2. prtClsID   

  メリット
    cmp 非依存
    2. 余計な cls に RTTI を埋め込む必要なし
    3. 組み込む情報を 自由に選べる


___

■ typeid

実行時のオブジェクトの型をしらべることができる
___

■ ダイナミックキャストを避ける

ダイナミックキャストを利用すると、利用者側のコードが if - else のロジックで複雑になる。 また新規のクラスが追加すると、拡張が必要になる。 そこで、各クラスの具体的な処理を一般化して基底クラスで仮想関数としてハンドラをつくってしまう。 POINT if - else, dynamic_cast のコードをみたら、仮想関数による動的コールにまとめてしまう。 プレースホルダーとなるクラスを抽出する。
    class Gui {
      public :
        virtual void draw();  
    };
次に具体的な処理を仮想関数にかく。
    class Button : public Gui {
      public :
        void draw();
    };

    class Text : public Gui {
      public :
        void draw();
    };
利用する側は どのクラスか調べる必要もなく、draw() を呼ぶだけですむ。
    drawGui( Gui &gui ) {
      gui.draw();
    }
仮想関数を利用しないと、巨大な if - else ブロックができる。
    drawGui() {
      if ( gui->getType() == "" ) {
        Button *b = (Button *)gui;
        b->drawButton();
      }  
      else if ( gui->getType() == "" ) {

      }
    }

___

■ ThisPointer


  DESC
     this は const ではない。変更ができる。
     なぜか ? this の中で当然. 自分自身を修正できるから
     ので const 関数に渡しても問題なし.



    this は CMP としては Foo *const という扱いになる

    &this はだめらしい ( '&' に左辺値がありません。)
   ie. アドレス演算子(&)のオペランドには左辺値( 代入できる式 )が必要ということ。
       ( 変数(箱)がないと, その場所を返すことができない )
    ClsFoo *p = 0;
    this = p;  // ERR ( this は左辺値ではない )

  POINT  
    SingleInheritance ( SI )に対しては this は不変.
    MultiInheritance  ( MI )に対しては this はかわる.


    func1 adr 22ef04  // int 1 個分のずれ. 
    func2 adr 22ef00
    func0 adr 22ef00
    func3 adr 22ef00


      
  POINT
    実は MemFunc へのアクセスは, this ポインタが仕込まれている
    memFunc( Foo *this );

    そのため内部で VarMem を利用しない場合は NULL を渡しても問題ない。
    Foo *f = 0;
    f->func(){ printf("test") };
___

■ utility class


  DESC
    static 共通処理をまとめたもの
    static == object のメンバ関数を編集しないもの
      
      printf();
      StrToken();
___

■ 継承(inheritance)


___

■ public.継承

public 継承した場合は 基底クラスへのキャストは安全にできる。 基底クラスの実装内容を再利用して、拡張したクラスを作るには public 継承を使う。
    class Gui {

    };
    
    class Button : public Gui {

    };
]  ]]

___

■ 正しく継承する

より少ない要件で、より多くの振る舞いをすることが正しい。 こうすることで、既存のシステムに新しいものを追加しても破壊されない。 逆に仕様を満たせば、中身は基底クラスと同じでなくてもよい。
___

■ 実装の継承とインターフェイスの継承

継承は2種類ある。
     実装の継承
     インターフェイスの継承
実装の継承とは クラスの属性、メソッドを基底クラスにまとめてしまうこと。 同じコードがあったときに、関数としてまとめるのと同じ。 複数のクラスに同じような、属性、メソッドがあればそれらをまとめて重複を減らす。
    class Gui {
      // 大きさ、位置などのパラメータはどの Gui ももっているのでまとめる。
      float x, y;
      float szx, szy;

      // メソッドも共通化できる。
      void setPosition( float x, float y );
      
    };

    // スライダ固有のパラメータのみを追加する
    class Slider : public Gui {
      
    };
インターフェイスの継承は実装を基底クラスからもらうわけではなく 呼び出し方法のみを継承する。 こうしておくと 呼び出し( システム )側が、各インスタンスのクラスごとに場合わけをする必要がなくなる またインターフェイスだけを知ればよくなるので、実装側のクラスのヘッダが不要になる。 知るべきことが減る。 カプセル化といって、知らなくてもいいことを知らないようにしておくことができる。
    class Gui {
      virtual void onClick() = 0;
    };

    class Button : public Gui {
      void onClick() {

      }
    };

___

■ 継承の使いどころ

if - else で似たようなコードがあったら継承の使いどころ 継承はクラスをグループ化する。
    window_event_callback( msg, type ) {

      if ( type == E_BUTTON ) {
         button->onClick( msg );
      }
      if ( type == E_BUTTON ) {
         text->onClick( msg );
      }
      if ( type == E_BUTTON ) {
         menu->onClick( msg );
      }

    }
同じようなコードがあるので、基底クラスで仕様だけを決めてしまう。 Gui であるすべてのクラスは onClick( msg ) をもっているというルールをつくる。
    class Gui {
      virtual void onClick( int msg ) = 0;
    };
派生クラスで具体的な処理を仕様にそってつくる。 Button は Gui の一種である。
    class Button : public Gui {
      void onClick( int msg ) {

      }
    };
システム側はまとめることができる。クラスごとに場合わけをせずに 基底クラスのインターフェイスにだけアクセスすればよくなる。
    window_event_callback( msg, type ) {
      gui->onClick( msg );
    }

基底クラスの Gui を作る必要がなければ メソッドを = 0 としてしまう。 こうすると 基底クラスで仕様だけを決めるときは、 間違って実体化できないようにしておく。 もし空の実装を用意しておくと、間違ってオーバーライドの忘れなどが発生してしまう。 そこで = 0 として中身がないことをコンパイラに教えて実装忘れがあった場合に怒ってもらう
    class Gui {
      virtual void onClick( int msg ){}
    };
REFERENCE 純粋仮想関数 インスタンスをつくれなくなる。
    Gui *gui = new Gui();
___

■ 関数のオーバーロード

派生先で同名のメンバ関数をつくると, オーバーライドはされずに基底クラスの関数が隠される。 そのため 派生先では同名の関数をつくらないようにする。
    class Base {
      public:
        void display();
    };

    class Derive {
      public:
        // これは基底の display() を隠す。
        void display();
    };

    Derive d;

    func( d, d );
    
    void func( Base &b, Derive &d ) {

      // Base::display() が呼ばれる。
      b.display();
      d.display();
    }

___

■ private継承

private 継承をすると基底クラスの public, protected が 派生クラスの private になる。 protected継承をすると同様に, protected となる。 いつも利用している public 継承は, 基底クラスの public は派生クラスの public になる。 POINT 使いどころは protected アクセスを追加したいとき また 基底クラスへのポインタに変換できる。
___

■ アクセス制御


    クラス内の情報をアクセス制御をかけるには、クラスのメンバ( 変数, 関数 )を
    アクセス制御をつける。
    
     public
     protected
     private    ( 個人の秘密使用 )
実装であるメンバ変数は private 権限にして, interface であるメンバメソッドを public にするのが主なアクセス制御になる。
    public:
        func();
    private:  
        int i;
POINT private にするということは、変更しても影響を与えないということ。 逆に public な箇所は、公開することになるので、簡単に変更ができないということ。
___

■ struct.class.の違い

struct は デフォルトレベルが public class は private
___

■ 例外(Exception)



   C++ にはエラーを処理するための機構として例外というものが用意されている。
   C スタイルの関数の戻値としてエラーを返す方法にとって代わる方法のこと。


    エラーがプログラムの実行中に発生した場合に
    例外オブジェクトというもの (これ自体がクラスのインスタンス)を生成します。 

    これを例外の送出(スロー)といい
    例外オブジェクトを適切な方法で補足(キャッチ)して、 エラー処理をする。

    例外をキャッチしたい範囲があれば try ブロックで処理をかいて
    catch でリカバリをする処理をかく。


     try  // 例外の発生し得る範囲
     {
       throw "例外が発生しました";  // 例外をスローする
     }
     catch( const char* str )  // 例外をキャッチする
     {
       std::cout < <  str < <  std::endl;
     }
catch ブロックには、キャッチできる例外の型を指定する。
    catch ( runtime_error ) {
      
    }

    // すべての例外型をキャッチする
    catch ( ... ) {
      
    }
WARNING この指定はできない。コンパイルエラーとなる。
    catch () {
    
    }
各関数はどの例外をなげるか宣言をする。 例外の仕様という。 throw() は例外を投げないことと宣言する。
    void func() throw();
throw( runtime_error ) は runtime_error 型( またはその派生型 )の例外をなげると説明をする
    void func() throw( runtime_error );
___

■ 例外の使いどころ

例外は無視できない。 例外をなげる場合は、どこかでキャッチをしないとプログラムが終了する。 つまりエラーがあればその場で即死させることができる。
    // エラーコードとして返す場合はチェックを無視できる。
    ErrorCode fileopen( string &path ) {
        if ( path ) {
          return E_INVALID_PATH;
        }
    }

    // 投げられた例外はどこかでとらえないとプログラムは終了する。
    void fileopen( string &path ) throw( InvalidFilePath );

    void fileopen( string &path ) {
        if ( path ) {
          throw InvalidFilePath( path );
        }
    }


制御ロジックがエラーハンドルロジックと分離できる
    try {
      add( a )
      add( a )
      add( a )
      add( a )
    }
    catch ( ) {
      // ここでまとめてエラーハンドル
    }
    try {
      ret = add( a )
      if ( ret ) {

      }
      add( a )
      // エラーハンドル
      if ( ret ) {

      }
      add( a )
      if ( ret ) {

      }
      add( a )
    }
    catch ( ) {

    }
___

■ 例外を捕捉する

全体で例外をキャッチするには main() 内でキャッチをする。
    int main() {
      try {

      }
      catch (...) {

      }
      return 0;
    }
もし main で捕捉できない例外があれば、main() の実行前に発生した例外かもしれない。 静的なオブジェクトのコンストラク内で例外をとらえる。
    MemoryManager gManager;

    


___

■ 例外処理をカスタマイズする

___

■ terminate

投げられた例外がキャッチされないと、 terminate() が呼ばれる。 エラーのログをとり, リソースをすべて解放をして abort() をよぶ。 文字とおり最後の処理をする。 set_terminate() によって実装を変更できる。
    void my_terminate() throw()
    {
      printf( "call my_terminate\n" );

      char buf[256];
      gets( buf );

      // エラーのログをとり、フラッシュする。
    }


    void testfunc() throw( runtime_error )
    {
      throw runtime_error( "test" );
    }

    int main() {
      set_terminate( my_terminate );
      testfunc();
    }

POINT main() 実行前に静的なオブジェクトの初期化が実行される。 このときは 静的なオブジェクトのコンストラクタに set_terminate() をいれると捕捉をできる。
___

■ unexpected

仕様にない例外をなげると, unexpected() をよばれる。 デフォルトの処理は terminate() をよぶだけ。 set_unexpected() によって内容を変更できる。
    unexpected() -> terminate() -> abort()
___

■ 例外クラスを捕捉する

例外はシステムで定義すみのクラスがある。 それ以外に任意の例外クラスを定義できる。 呼び出し元は自分がエラーハンドルできる例外型を指定できる。

    init() {
      try {
        File->open();
      }
      catch ( InvalidFileException ) {
        // InvalidFileException とその派生クラスの例外だけをとらえる。
        // それ以外の例外は無視されて、さらに上の関数へ伝播する
      }
    }



    void main() {

      try {
        init();
      }
      catch ( runtime_error ) {
        // init() 以下で捕捉されない例外はここに届く。
      }

    }
    

POINT catch で捕獲できる例外オブジェクトは任意の型を補足できる。 派生クラスもキャッチの対象になるので階層構造にしておくと便利。 throw; とするとキャッチした例外を再度スローすることになる。 つまり人に丸投げすることになる。
    catch {
      throw;
    }
try - catch をするのは次の条件をみたすとき。 すべての関数よびだしで try - catch をする必要はない
     例外をなげる可能性があるとき
     その例外をリカバリーできるとき
WARNING リカバリーできない例外をキャッチするのは問題を先送りにしているだけ
    try {

    }
    catch () {
      // 何もしない
    }
例外がなげられたときは スタック上のオブジェクトは デストラクタが実行される
___

■ 例外クラスを定義する

POINT 例外は 基底クラスから必ず派生させる。 こうすることで main でキャッチオールブロックを用意できることになる
    int main() {
      try {

      }
      catch( exception e ) {

      }
    
    }
システムが提供する 例外クラスもある
    #include< stdexcept> 
    #include< exception> 

     runtime_error
     overflow_error
     underflow_error
    class InvalidPath : public runtime_error {
      public:
        InvalidPath() throw();
    };

___

■ コンストラクタの例外

コンストラクタも例外をなげることができる。 コンストラクタで例外を投げるということは そのオブジェクトが未完全な状態でつくられる。
    T::T() throw( runtime_error )
    {

    }

メンバオブジェクトのコンストラクトに失敗した場合は、 既にコンストラクト済みの他のオブジェクトのデストラクタがよばれる。
___

■ アンワインドプロセス

例外の実装は longjmp() と同じ。 関数外の場所に制御をうつす。 ただし 例外は スタックを戻してくれる。( unwind process ) スタック上のオブジェクトは デストラクタが実行される。 POINT ただし /EHsc オプションをつけること 指定しないとデストラクタが実行されない。


___

■ GetCurrentProcessId

SYNTAX DWORD GetCurrentProcessId(); DESC 呼び出し側プロセスのプロセス識別子が返す。 Kernel32.lib
___

■ internal

___

■ SymGetLineFromAddr

SYNTAX BOOL SymGetLineFromAddr( HANDLE hProcess, DWORD dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE Line ); DESC 指定されたアドレスに対応するソースコードの行を検索する imagehlp.lib
___

■ GetFirstStackTrace

___

■ symgetodulebase

SYNTAX DWORD SymGetModuleBase( HANDLE hProcess, // 最初に SymInitialize() へ渡された、プロセスのハンドルを指定する。 DWORD dwAddr // SymLoadModule() を使ってロードしたモジュールのいずれかに含まれている有効な仮想アドレスを指定する。 ); DESC 指定されたアドレスを保持するモジュールのベースアドレスを取得する。
___

■ SymLoadModule

DWORD SymLoadModule( HANDLE hProcess, HANDLE hFile, PSTR ImageName, PSTR ModuleName, DWORD BaseOfDll, DWORD SizeOfDll ); DESC シンボルテーブルをロードします。
___

■ インライン(Inline)


    関数の中身を呼び出し元にインラインする(埋め込む)時に利用する。
    
    C ではマクロでも代用できるが, () をつけないとバグの元になるため Inline を利用するとよい。
    
  POINT
    インライン化する目的は主に関数コールのオーバーヘッドをなくして高速化するため。
    
  POINT
    コンパイルする cpp 単位で展開するため関数の定義は見えていないといけない。
    文字通り[ inline == 埋め込む ] のでヘッダに記述しなければ参照できない。

    // test.h
    inline int add( int i );
定義部分が見える必要がある。
    // test.h
    inline int add( int i ) {
      return i + 1;
    }
    int main() {
        int i = add( 10 );
    }

    // 次のように展開される(かもしれない)
    int main() {
      int i = 10 + 1;
    }
___

■ inline化する

関数を inline するには次の条件をみたすようにする
     関数の定義部分が見えるようにする。
明示的に inline するように宣言する
    inline int add( int i ) {
      return i + 1;
    }
クラスメソッドの場合はクラスの定義部分でメソッドの定義をかくと暗黙で inline を宣言する。
    class Test {
      void int add( int i ) {
        return i + 1;
      }
    }
POINT inline の指示はコンパイラの要求であるので、実際に inline 化するのはコンパイラが決定する。
___

■ インライン化する

実行コードのサイズはインライン化する関数の大きさによって大きくなったり小さくなったりする。 関数が小さいときは inline 化することで関数呼び出しのオーバーヘッドのコードが減るため小さくなる。
    cl /c /FX  main.cpp
またコンパイラが最適化のために勝手に関数をインライン化することもある。 グローバル最適化をすると発生する。
___

■ インライン化で減るコード

     パラメータの push pop に関連するコード

PageFault がおこる可能性が減る。 ページフォルトとは 仮想メモリOS上でコードがメモリ上にない場合に発生する。
___

■ インライン化すべき条件

インライン化するには次の条件をみたすかチェックする。
     関数が十分に小さい。
     たくさん呼ばれる。
     コードの中身の変更が少ない。
          ヘッダに定義をかくので、インクルードするすべてのファイルにコンパイルが必要になる。
WARNING 開発の段階でインライン化するとヘッダファイルを変更することになるので 大規模な再コンパイルが必要になる。
___

■ OpaquePointer(オペークポインター)




  DESC
    不透明なポインタ. ( == 実装が見えない Pointer )
        
    // 不完全型
    class MyClass;    

    後は Pointer として扱えればいい場合のみ利用できる

    クラス xxx は 不透明である という


    class Test {

      public:
        // interface

      private:
        void *data;
        class *Impl;
    };



    // 公開するのは CGparameter
    //  実装 struct _CGparameter は見えない
    typedef  struct _CGparameter  *CGparamter;

___

■ TinyXml



  
    #include "tinyxml.h"
    #pragma comment(lib, "./debug/tinyxmld.lib")

    {
      TiXmlDocument doc;

      TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );
      TiXmlElement *element = new TiXmlElement( "Hello" );

      // エレメントを作成してアトリビュートを設定
      TiXmlElement *e = new TiXmlElement( "node" );
      e->SetAttribute("name", "test");

      TiXmlText * text = new TiXmlText( "World" );

      // 各ノードを親子づけする
      element->LinkEndChild( text );
      element->LinkEndChild( e );
      doc.LinkEndChild( decl );
      doc.LinkEndChild( element );

      // 保存する。
      doc.SaveFile( "test_write.xml" );  
    }
XML は次の仕様をみたす必要がある root ノードはひとつ。
    < root>
      // 同一の attribute はダメ
      < node name="xxx" name="yyy">

    < /root>

    // これはダメ
    < root/>
___

■ ReferenceCount(リファレンスカウント)


    リファレンスカウントとはオブジェクトの寿命をコントロールする方法のこと。

    オブジェクトは誰かから参照されている間は、生き続けて、誰からも参照されなくなったら死ぬ、
    という考えで実装する方式のこと。

    Java や C# では言語レベルでこの機能を提供するため
    明示的に delete を呼ぶ必要がない。

    問題となるのは誰がオブジェクトを作成して、破棄するかということ。
    通常は オブジェクトを作成した人が破棄する。
    



しかし、複数の人が参照し始めると、勝手に削除することも危険になる。 そこで、オブジェクト自身が削除するという方式ができた。
___

■ ReferenceCount

    Object *A = new Object();

    // 別のポインタからも参照させる。この時点で [ A, B ]の2つから参照される。 
    {
      Object *B = obj;

      // B からも見ているよ、ということを伝える。
      B->addRef();

      // 参照先は責任をもって release() をよんで不要になったことを伝える。
      B->release();
    }

    // ここで誰からも参照されなくなるので、自分自身で自分を消去する。
    A->release();
    class Object {

        Object() : m_cnt(1) {

        }

        void addRef() {
          m_cnt ++;
        }

        void release() {
          m_cnt --;
          if ( m_cnt == 0 ) {
             delete this;
          }
        }

      private:
        int m_cnt;
    };
WARNING リファレンスカウントは 適切に addRef と release が呼ばれないと delete 忘れや ダングリングポインタ と同じ現象がおきる。 そこで 呼び出し側に操作させずに、少し賢いポインタを渡してあげる。 REFERENCE SmartPointer REFERENCE SharedPointer
___

■ SmartPointer(スマートポインタ)


  DESC
    ネイティブのポインタをラップし、参照カウントがゼロになったときに
    ポインタの参照先を自動的にdelete するクラスのこと。

    自動削除ポインタのこと。

    ポインタのような振る舞いをするクラスのこと。


  POINT
    解放忘れを防ぎたい場所でする。
    destructor のタイミングで自分が管理しているオブジェクトを解放する。
    ptr が削除されると, 参照先も自動で削除される ptr

      {
        // stack 上に SmartPointer がのる。
        std::auto_ptr< Test> p( new Test() );

          
      }  // スマートポインタオブジェクトが消滅すると Test のインスタンスは削除される。
WARNING スマートポインタはコピーをするとコピー元は NULL になる。

    class Test
    {
     public:
      Test() {
        printf( "ctor\n" );
        m_data = new char[1024];
        sprintf( m_data, "test" );
      }
      ~Test() {
        printf( "dtor\n" );
        delete m_data;
      }

      void func() {
        printf( "func %s\n", m_data );
      }

     private:
      char *m_data;
    }; 


  {
    auto_ptr< Test> p( new Test() );
    p->func();

    printf( "check Pointer %d\n", p );

    printf( "copy" );
    auto_ptr< Test> b = p;

    printf( "check Pointer %d", p );

    // p は NULL なのでクラッシュする。    
    p->func();
    b->func();
  }

___

■ スマートポインタの使いどころ

例外や if 文などの複雑なロジックがあった場合でも簡単にかける。 delete 文を省けるというよりも、どんな場合でも解放忘れがないというメリットがある。 POINT 同一スコープでアロケート、デアロケートする処理があったら使いどころ。 Python の with ステートメントみたいなもの REFERENCE with REFERENCE Dispose

      // 次のような状況でも解放漏れがおきない。
      // 解放の処理を明示する必要がない。
      {
        void func() {
          auto_ptr< File> file( new File("d:/test.txt") );
          
          try {
            if ( ... ) {
              // ここでファイルを閉じる
              return;
            }
            else if ( ... ) {
              // ここでも
              return;
            }
          } catch () {
            // ここでも
          }

          // ここでも
        }
      }
      
      
POINT boost::shared_ptr : 内部に参照カウンタをもつため 譲渡できる。 Decoration Pattern のひとつ WARNING auto_ptr ではひとつのインスタンスを複数の auto_ptr でシェアできない。 そこでコピーを禁止しておく。 ( STL 禁止 == vector< auto_ptr< T> > ) 次の場合に問題がおきる。
   auto_ptr< Test> p( new Test() );
   {
     auto_ptr< Test> pp;
     pp = p;  // 譲渡 
     
     // p が指す obj がpp の破棄によって解放 
   } 
    // インスタンスは解放すみ

___

■ 共有できるスマートポインタ

POINT 共有できない欠点を取り除いたものが shared_ptr 生のポインタと比べて次のことができる。
    // コンストラクト時に NULL にセットするので未初期化のポインタがなくなる

    SmartPointer() : m_ptr( NULL ){}

    // 
    SmartPointer< int> p;

    // ここで死んでくれる
    *p = 10;

___

■ SharedPointer(シェアードポインタ)


  DESC
    SmartPtr のコピーの問題点を改良したポインタクラスのこと。
    参照カウンタをもち, どの変数からも参照されない時点で解放する。


    ThreadSafe な設計である. ( CntRef の操作時に排他制御がされる. )
       -> ( SharedPointer を Thread( Worker ) で共有しなければ OK  )

  POINT
    生のポインタをかえすかわりに, SharedPointer を返せば OK 

     // ヒープにTestオブジェクトを生成
     // この時点で参照カウントはこの時点で1である
     boost::shared_ptr< Test> p(new Test());  // p.cntRef = 1;

     {
       boost:shared_ptr< Test> pp;

       // スマートポインタをコピーする(参照カウントが+1される)
       pp = p;       // pp.refCnt = 2; p.refCnt = 1;  // 相手先は cntRef を copy してさらに ++ !
       std::cout < <  "pp will destruct" < <  std::endl;

       // このスコープを抜けたときにppはなくなり ppが指しているTestオブジェクト
       // への参照カウントは-1されるが 、まだ0ではないためTestオブジェクトは開放されない。
     }

     // pが指しているTestオブジェクトはまだ開放されていない


    ButtonRef Button::create()  // RawPointer のかわりに返す。
    {
      return ButtonRef( new Button() );
     }

    class Window {

      ButtonRef m_button;   
     };      
  
    // 自動的に joint も削除される
    delete wnd;  
___

■ shared_ptr

    template<  class T >
    class SharedPtr {

      public:
        SharedPtr( T *ptr ) : m_ptr(ptr), m_cnt( NULL ){
          m_cnt = new int;
          *m_cnt = 1;
        }

        // 死ぬときに参照数をへらす。
        // 0になったら 実体を解放する。
        ~SharedPtr() {
          release();
        }

        // SharedPtr 同士のコピーをする場合は参照数が増やす。
        void operator=( SharedPtr &rhs ) {

          // 今指している参照を離す。
          release();

          // 相手と同じ参照をもつ。
          m_cnt = rhs.m_cnt;
          m_ptr = rhs.m_ptr;
          (*m_cnt) ++;

        }

        void release() {
          (*m_cnt) --;

          if ( *m_cnt == 0 ) {
            delete( m_ptr );
            delete( m_cnt );
          }
        }

      private:
        // 実体
        T *m_ptr;
        
        int *m_cnt;
    };
___

■ デバッグ


___

■ ポインタ解放忘れを防止する

生のポインタをクラス内で管理することで解放忘れを防止する。 デストラクタを利用することで自動で解放してしまう。 REFERENCE SharedPtr REFERENCE SmartPointer
___

■ クラス内で自己診断をする

クラスの正当性をチェックするメソッドをつくる。 assert などと併用すると リリース時にテストを除去できる。 コンストラクタとミューテータで実行する。 また通常のドキュメントとくらべると曖昧性がない。
___

■ 例外コード


___

■ c0000094

0除算をした。
___

■ ポインタ


  POINT
    wildpointer はでたらめな位置を書き込み、既存のオブジェクトを破壊する。
    ほとんどは運よく、OSがプロテクトする領域を書き込もうとしてプログラムはクラッシュする。  


  WARNING 
    ローカルオブジェクトの参照を返すのはワイルドポインタをつくる。
    ローカルオブジェクトはスタック上に生成されるため
    関数が終了した時点で破棄されることになる。

    Vector &func() {
      Vector v;
      return v;
    }

    // BAD
    const &T  min( const T&a, const T&b )

    // OK
    T  min( const T&a, const T&b )
WARNING リファレンスパラメータの参照を返してはいけない。
    const string &s = unsafe( createTmp() )
    cout < <  s;
WARNING NULL ポインタがすべて 0 bit で埋まる保障はない。( ほとんどの環境では 0 だが ) POINT const リファレンスを返すのは 余計なコピーをなくして処理を高速化するため
___

■ CPPでよくある間違い


___

■ ポインタの2重解放

___

■ コピーのかわりにmemcpyを使う

POINT クラスがリファレンス先( ポインタ )をもつ場合は 単なる bit 単位のコピーでは論理的なコピーにならない。
    string a = "test";
    string b = a;

    // リファレンス先が共有されるので2重に解放される。    
    memcpy( &b, &a, sizeof(a) )
realloc も同様にストレージが移動する際は bit 単位のコピーが必要になる。 オブジェクトの配列を利用するときには注意すること。
___

■ タイプセーフでない関数をつかう

クラスのインスタンスは場合によって仮想関数テーブルのポインタをもつため "型を無視した操作" は破壊する可能性がある。
    class T {
      public:
        virtual void vfunc(){}
    };

    void test( T *ptr ) {
      // 仮想関数をコールすると落ちる。
      ptr->vfunc();
    } 
        
    T obj;
    memset( &obj, 0, sizeof(T) ) ;
    test( &obj );
___

■ コピー操作によってリソースを2重に開放する

    class String {
     public:
      String() : m_data( new char[256] ){}
      ~String() {
        printf( "dtor %X\n", m_data );
        delete m_data;
      }

     private:
      char *m_data;
    };

    {
      String s;
      {
        // ここで m_data がコピーされるので 2重に delete される。
        String st = s;
      }
    }  

そこでポインタを内部にもつクラスはコピーする気がないならばコピーを禁止をしてしまう。 コピーさせないか、DeepCopy をさせる。
    private:
      String( const String &);
      void operator =( const String &);
___

■ リソース管理


___

■ ポインタ変数はnewをした後にdeleteする

delete をした後のポインタ変数はすぐに、安全な状態にする

    // p の指す先を解放したら 
    delete p;

    // p をリセットする。
    p = NULL;

    // ここで即死してくれる。
    p->func();

___

■ リファレンスカウント

ヒープにアロケートしたオブジェクトを解放する処理を 自分自身にやらせる。
    class Resource {

      public:
        create();


      private:
       int m_cnt;
    };


    // Resource オブジェクトの管理機能つきポインタ
    class ResourcePtr {
      public:
         ResourcePtr( Resource *p ) 

        ~ResourcePtr() {
          m_ptr->m_cnt --;

          if ( m_ptr->m_cnt == 0 ) {
            delete m_ptr;
          }
        }
      
      private:
        Resource *m_ptr;
    };

REFERENCE コンストラクト方法を制御する
    {
       ResourcePtr *p = Resource::create();

       // 好きなだけコピーできて
       p2 = p1;

       func( p2 );

       // 誰からも参照されなくなったら自動で解放される。
       
    }

    
    


___

■ コピーオンライト

コンピュータプログラミングにおける最適化戦略の一種である。 コンピュータ内部で、 ある程度大きなデータを複製する必要が生じたとき、 愚直な設計では、 直ちに新たな空き領域を探して割り当て、コピーを実行する。 ところが、もし複製したデータに対する書き換えがなければその複製は無駄だったことになる。 そこで 複製を要求されても、コピーをした振りをして、 とりあえず原本をそのまま参照させるが、 ただし、そのままで本当に書き換えてはまずい。 原本またはコピーのどちらかを書き換えようとしたときに、それを検出し、その時点ではじめて新たな空き領域を探して割り当て、コピーを実行する。 これが「書き換え時にコピーする」 基盤となる考え方は、複数の(何らかの)要求者がリソースを要求するときに、 少なくとも当初はそれらの要求を区別する必要がないときに同じリソースを与える、というものである。 これは要求者がリソースを「更新」しようとするまで保持され、「更新」が他者に見えないようにリソースの 個別のコピーを必要になった時点で作成する。 要求者からはこの一連の動きは見えない。 第一の利点は要求者が全く更新しなければ、個別のコピーを作成する必要が生じないという点である。
___

■ ユーザーコードからポインタを隠す

リソースの管理をクラス内にカプセル化してしまう。
    // このスコープを抜ければ、file オブジェクトのデストラクタが解放してくれる。
    {
      File file( );
      file->readLine();


    }
リソースが見れると漏れが起きる。
    FILE *fp = fopen();
    
    fgets( fp, )
    
    fclose( fp );
___

■ オブジェクト指向


    柔軟性がたかく、変更に対処しやすいコードをつくるための技術とか設計方法のこと。
    

     抽象
     カプセル化
     わかりやすさ
     変更性
     再利用性

仮想関数を使うと システム( よびだし )側に変更をせずに、新規要素を追加できる。


___

■ オブジェクト

コードとしてみれば、あるメモリ領域であって、 設計段階ではプラグラムする対象をクラスとして切り出す単位。
___

■ コンポジション

コンポジションを使うと既にあるモジュールを組み合わせてプログラムをつくることができる。
___

■ ポリモーフィズム

基底クラスの参照をつかって、派生クラスのオブジェクトのメソッドを動的に呼び出すこと。 仮想化したインターフェイスを用意しておけば、将来の追加をうけいれることができる。
___

■ インターフェイス

利用者側のコードからかくこと。テストコードとか、サンプルコードをかく。 そうすると実装を見せずにすむ。 外側からみえるコードを先にかく。それがクラスのインターフェイスになる。 またインターフェイスは利用者が見るところなので 情報は少ない方がよい。 そうすると使う側( つくった本人も含む )も簡単に使い方を覚えることができる。
___

■ アクセッサを多用しない

set/get とメンバ変数( 実装 )を無闇に関連づけない。 必要なインターフェイスのみを公開すること。
___

■ 継承をインターフェイスの継承につかう

基底クラスの実装を再利用するために、継承を利用しないで インターフェイスを継承するために使う。 こうすると 既存のシステムが基底クラスの参照をとって処理をしている部分の 変更がいらないのでシステムが安定する。 POINT 既存コードに影響を与えずに 新しい派生クラスを追加することが目標。 そのためにシステムは 基底クラスの参照をパラメータにとるようにする。 インターフェイスはシステムから見ると、意味があって一貫性のあるまとまりとして切り出すこと。 そうすると派生クラスをつくりやすくなり、 if - else のコードが減る。 POINT インターフェイスを再利用するということ。
___

■ ポインタをつかって間接レイヤーをつくる

インターフェイス( 間接レイヤー )を余計につくると、その部分が可変になる。 インターフェイスと実装をわけるとは、ポインタ経由するということ。
___

■ インターフェイスをきりだす

インターフェイスを切り出すには "類似性" に注目をすること。 配列とか map などのコンテナの実装ではなく、ソートされた要素の集合とみなすと インターフェイスができる。 ユーザーは実装ではなく、インターフェイスに対してコードをかく。
___

■ 設計の基本原理

不要な結合をへらすこと 設計をしないと一貫性のない、その場しのぎの決定による偶然の産物になる。 一番変化がありそうな部分に柔軟性を確保すること。 柔軟性を確保すると複雑になるのですべての部分で確保をしないこと。
___

■ フリーストア

new をつかって確保されるヒープのこと。
___

■ mutate

オブジェクトを変化させること。
___

■ throughput(スループット)

処理量, 処理能力, スループット《所定の時間に処理工程を通過する素材の量
___

■ latency

待ち時間 呼出し時間 データを転送する命令を出してから実際に転送が開始されるまでの時間 POINT File IO, Network IO が特にレイテンシが大きいので、この空き時間を利用して別のことをする。
___

■ friend(フレンド)


    フレンドには3種類ある
     フレンド関数
     フレンドメンバ関数
     フレンドクラス
フレンドは次の場合につかう
     2つ以上のクラスが連携してうごき、互いの実装にアクセスをするとき
     実際は1つのクラスだが 寿命やインスタンスの数が違うときにつかう

    

___

■ フレンド関数

フレンド関数とはクラスの public 以外のメンバにアクセスできる 非メンバ関数のこと。 friend 関数を宣言するアクセスレベルはどこでもいい。 コンパイラはアクセスレベルの指定は考慮していない。

    // 以下のどれでも同じ。
    class Vector {
      public:
        friend  ostream &operator < <  ( ostream &o, const Vector v );
      protected:
        friend  ostream &operator < <  ( ostream &o, const Vector v );
      private:
        friend  ostream &operator < <  ( ostream &o, const Vector v );
    };

___

■ フレンド関数のつかいどころ

本質的にはメンバ関数とかわらない。( メンバ関数は public 以外にアクセスできるから ) フレンド関数にするには、利用者側のコードが直感的になるようになるときに使う。 そのため本来、メンバ関数であるべきものを、フレンド関数にするといい。
     演算子の右辺にくる場合
     
    class Vector {
    public:
      friend  ostream &operator < <  ( ostream &o, const Vector v );
    };


    ostream &operator < <  ( ostream &o, const Vector v ) {
      return o < <  v.x < <  " " < <   v.y < <  " " < <   v.z < <  endl;
    }

    {
      Vector v;
      cout < <  v < <  endl;
    }

___

■ フレンド関数を仮想関数にする

フレンド関数は仮想関数にできないので、フレンド関数側で、仮想関数をよびだすことで実現する。
    class Gui {

      public:

        friend ostream & operator< <  ( ostream &o, const Gui &gui );
      protected:
        // 実体
        virtual void print( ostream &o ) const = 0;
    };

    ostream & operator< <  ( ostream &o, const Gui &gui ) {
      gui.print();
    }

    class Button : public Gui {

      protected:
        virtual void print( ostream &o ) const {}
    };
___

■ フレンドクラス

あるクラスが別のクラスに private アクセスを許す場合は次のようにかく
    // Base クラスは T からのアクセスを許可する
    class B  ase {
      frie nd T;
    };    

                       
派生クラスは friend 関係を "継承しない"。 ( 許可すると派生してしまえばすべてアクセスできることになるから )
    class Derive : public Base {

    };
___

■ フレンドクラスのつかいどころ

クラスの特徴をユーザーからは隠したいが、特定の関連クラスにだけ公開したい場合に使う。 プライベートクラスとして使える。 プライベートクラスは実装のためだけに使うクラス。 これを使うと、名前の重複を防ぐことができる。
    class LinkList {

      // クラス Node は LinkList 固有のため内部のスコープにしてプライベートにしてしまう。
      class Node {

        friend  Node;

        
      };
    }

___

■ 仮想関数


    基底クラスのポインタをつかってメソッドを呼ぶと
    そのインスタンスのメソッドが呼ばれる

    以下のような処理をコンパイラがしてくれる。
    インスタンスの中には自分がどのクラスであるかという情報が入っている。
    dynamic_cast はこれを利用している。

    class Base {
    
      void func() {
        if ( m_type == 'A' ) {
          A *a = reinterpret_cast< A*>(this);
          a->func();
        }
        else ( m_type == 'B' ) { 
          A *b = reinterpret_cast< B*>(this);
          b->func();
        }
        
      }

    }

___

■ COM


    COM とは Windows 標準の共通のオブジェクトのコンポーネント
    COM をつくると Windows 環境で再利用可能なコンポーネントをつくることができる。


     言語に依存しない
     バイナリ形式

    
    C++ コンパイラがすることを自前でする。

    

___

■ 名前

COM は名前を一意にもつ。 これを GUID といい、世界中で開発されたコンポーネントとの重複をふせぐ。 GUID は 128bit の数値ID which guidgen.exe をつかって guid を生成する。 コンピュータのネットワークカードの uniq id を使って生成をする。
___

■ COM.の問題点

わかりずらい
___

■ インターフェイスとは

実装をもたない仕様のこと C++ でいえば関数ポインタテーブルのこと。 純粋仮想関数の集合
___

■ IUnknown

すべてのインターフェイスの基底くらす
___

■ COMクラスとCOMインターフェイスは全くの別物

___

■ IUnkowon.インターフェイス

インターフェイスの基底 3つの method をもつ
    class IUnkowon {
      public:
        virtual HRESULT  QueryInterface( REFID  rid, void *ppv ) = 0;
        virtual unsigned long   AddRef() = 0;
        virtual unsigned long   Releaes() = 0;
    };

POINT リファレンスカウントは オブジェクトの寿命を管理する方法のひとつ
___

■ COMInterfaceの定義

COMInterface をつくるには次の方法がある。

   C++ 抽象基底クラスとして定義する
   マクロをつかう
   MIDL を使う
___

■ C++

marshal(整列させる) C++ 以外の呼び出し元から呼べなくなる。
___

■ マクロをつかう

言語, OS の差異を吸収できる。
    STDMETHOD( Push ) PURE;


___

■ MIDL

言語に依存せずに インターフェイスを定義できる プロキシとスタブを自動生成する。 このため プロセス間通信で必要な処理を自動でしてくれる。 別プロセスの関数を呼ぶということ。 別プロセス間での通信処理をしてくれる。
___

■ COM.のエラー

1 bit エラー | OK 15 bit エラーコード 16 bit リターンコード 問題点は 関数の呼び出し側が常にエラーコードをチェックする必要があること。 REFERENCE Exception
___

■ バージョン

COM はバージョンを管理しない インターフェイスを変更すれば、それは新しい ID をもつインターフェイスとなる
___

■ COMの概要

COMInterface 特定の COMClass とは完全に独立している。 COM クラス ( COMInterface を実装したもの ) コードの本体。 CLSID をもつ COM オブジェクト COM クラスのインスタンスのこと。 StandardInterface マイクロソフトがプリセットで提供する COM のインターフェイスのこと。 CustomInterface 自作した COM interface のこと。
___

■ COMClass.をつくる

C++ で COMClass をつくるには次のようにする。
    class CoStack : public IStack {
      // IUnknown
      STDMETHOD ( QueryInterface )( REFIID  riid, void *ptr );
      

      // IStack

    };


    STDMETHODIMP    CoStack::QueryInterface( REFIID  riid,  void *ptr ) {
      if ( riid = IID_IUNKOWN ) {

      }
      else if ( riid = IID_ISTACK ) {
         *ptr = this;
      }
      else {
         *ptr = NULL;
      }

      AddRef();

      // ステータスコードを返す
      return S_OK;   
    }
___

■ オートメーション機構

JScript, VBScript ------------------------- オートメーション機構 ( Automation ) ------------------------- COM < ---- C, C++ からアクセス ------------------------- スクリプトツールが 低レベルの COM を利用できないときに使う。 スクリプトと COM (バイナリ)の糊付けのために使う。 スクリプトから利用してもらうには、IDL をつかって interface を記述してあげる。 WARNING 型は Automation 互換型である必要がある。 各プロパティとメソッドは DISPID をもつ。
    properties:
      [id(1), propget] boolean Empty;
    methods:
      [id(2)] void Push( long value );
      [id(3)] long Pop();

実際によばれるのは IDispatch インタフェイスによって機能する。
    interface IDispatch : public IUnkowon{
      
      // 名前(文字列)から DISPID をひく
      virtual  HRESULT   GetIDsOfNames( .... ) = 0;
      
      // プロパティへのアクセスをする
      // 一度取得した DISPID は保存される。
      virtual  HRESULT   Invoke();

    };


POINT Invoke は printf に似ている。 interpreter として機能する。 つまり小さなプログラムをかいている。 COMObject のうち DispatchInterface を提供するものを AutomationServer という。 これを使う コントローラは AutomationController という。 COMObject は DLL ( InProcessServer ) または EXE( OutOfProcessServer )として実装することもできる。
___

■ DualInterface

DispatchInterface と VtableInterface の両方をもつもの 呼び出し元は好きな方を選択をできる。 -------------------------------- COMInterface DualInterface --------------------------------
___

■ MetaData

インターフェイスとクラスの情報のこと。 ( reflection )のこと。 あるクラスに対して、どんな機能をもつか調べることができること。 TypeLibrary には COMInterface , COMClass の定義が含まれている。
___

■ COM.と.C++の違い

C++ : レジストリを利用しない COM : クラス , interface, TypeLibrary といった静的な情報を保存する。 C++ : new で生成したオブジェクトは delete をつかって破棄をする。 COM : Object 自身を削除することはない。 interface ポインタが不要になったら削除をする。 COM オブジェクト自身が削除をする。
___

■ TypeLibrary

コンパイルされた IDL ファイルのこと。 プログラムからアクセスできる。 これによって どんな情報をもつか わかることできる。 LIBID という ID をもつ。 スクリプト言語で役にたつ機能
___

■ ディスパッチインターフェイス

JScript と COM を連携するために使う プロパティとメソッドを公開するには activeX コントロールにする必要がある。
___

■ ActiveX

コントロールとは 1つの プログラムのコンポーネントのこと。( GUI の意味ではない ) VBX ---> OLE ---> ActiveX ActiveX は ディスパッチインターフェイスを通して プロパティ, メソッド, イベントを 公開する。 イベントとは 名前、パラメータ 戻り値 をもつメソッドのようなもの。 ActiveX のボタンがクリックされると イベントが発生する。 コントロールコンテナによって実装される。 各イベントはメッセージキューにいれられるので非同期に処理される。 ActiveXControl の特徴 DispatchInterface をとおして property, method, event を公開する。 ( AutomationObject のこと )
___

■ コントロールコンテナ

ActiveX コントロールを含むことができるコンポーネントのこと。 コントロールの存在を検索したりするのが仕事。 コントロールカテゴリによって レジストりに分類される。
___

■ COM.の使い方

    // 必要な CLSID は COM の作成者側が提供する。


    // 初期化をする( COM ライブラリをロードする )
    HRESULT  hr  =  CoInitialize( NULL );

    
    {
      // COM オブジェクトを CLSID を指定して作成する
      HRESULT hr = CoCreateInstance( CLSID_CoStack, NULL, IID_IUnkown, ptr );

      // 指定したインターフェイスを取得する。なければ NULL が返る。
      hr = ptr->QueryInterface( IID_STACK, ptr_stack );

      
    }

    
    
    // 後処理をする
    CoUninitialize();
___

■ クラスオブジェクト(ClassObject)

すべての COMClass は ClassObject をもつ。 これはメタクラスとして機能する。 クラスオブジェクトは システムレジストリに登録されて、オブジェクト生成に利用される。 すべての COMClass と ClassObject は COMサーバ内にある。 COMサーバ( DLL, EXE )内にある、実行可能形式なコードのこと。 IClassFactory を実装する。
    class CoStackClassObject : public  IClassFactory {
      public:
        STDMETHOD(CreateInstance)( IUnkowon *outer, REFIID riid, void *ptr );

    };
     STDMETHOD(CreateInstance)( IUnkowon *outer, REFIID riid, void *ptr )
     {
       if ( outer != NULL ) {
         CoStack *p = new CoStack();

         return p;
       }
 

     }

___

■ 言語に非依存

COMInterface は メモリレイアウトが バイナリ形式であるため 言語に依存しない。 COMInterface は関数ポインタのテーブルにすぎない。 C++ クラス定義をみて, コンパイラが仮想関数テーブルを作成してくれる。 C struct と 関数へのポインタを使って実現できる。
___

■ 位置に非依存

別プロセスにある場合でも proxy, stub を経由して実行される。
    よびだし元 ---> proxy ----> stub ---> COMClass
proxy オブジェクトがパラメータを送信する。 stub オブジェクトがパラメータを受け取り、 COMClass の関数をよびだす。 その結果を proxy に送る。
___

■ DCOM

RPC( Remote Procedure Call )をベースにしている。
___

■ COMの使いどころ

呼び出し元と COMClass が別の言語でかかれるときに使う。
___

■ CORBA

異なるコンピュータ, 言語でかかれたオブジェクト同士間で利用できる。 IDL は実装言語ではなく仕様言語 Proxy パターンを利用して, 言語非依存を実現している。 機種依存をしない形のデータ型をもつ。 CORBA::long は 4byte sizeof( long ) は機種依存のため 4byte とは限らない。
___

■ marshaling

marshaling とは異なるマシン間で呼び出しをする場合に パラメータを適切なバイナリ表現形式にすること。 IIOP

NINJAIDX 12