配列
オブジェクトの配列も通常の配列と同様に宣言する。={..}の中でコンストラクタ関数を呼び出すことで初期化も可能。
コンストラクタ関数の引数が一つの時は引数を並べたものを渡せばいい
class-name array-name[array-length] = {class-name(a1,a2..), ...}//引数が複数あるとき class-name array-name[array-length] = {a,b,c,}//引数が一つの時 class-name array-name[array-length1][array-length2] = {...} //二次元配列 //初期化用に与える値は多次元配列でも一次元で渡す
cの配列って2×3の配列aがあったとき、メモリ上にはa[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2]という感じで順番に並んでいるというのを、すっかり忘れてた。なんか多次元配列って、ポインタの配列だとばかり。
オブジェクトのポインタ,thisポインタ
構造体と同様メンバには->でアクセスする。オブジェクトの配列へのポインタをインクリメントした場合、次の要素を差すポインタになる。
クラス内でメンバを呼び出すときは暗黙的に呼び出し元のオブジェクトを差すthisポインタが参照されている。
なんとなくこのあたりの感覚はjavascriptに似ている気がする。
newとdelete
C++ではメモリを割り当てる方法として、mallocとfreeの代わりに、より安全なnewとdeleteという演算子が用意されている。
p-var new type; p-var new type(initial-value);//initial-valueを初期化 delete p-var;
mallocと比べたときの利点は以下
- new演算子はオブジェクトを格納するのに十分なメモリを自動で割り当てる。mallocのように自分で指定する必要がない。
- new演算子は指定した型のポインタを自動で返す。mallocの用に明示的にキャストする必要がない。
- newもdeleteもオーバーロードできる。
new,deleteを使って一次元配列を扱う
p-var new type[size];//動的に割り当てた配列の初期化は出来ない delete [] p-var;
なんで配列をdeleteするとき [] を付けなくちゃいけないんだと思ったけど、つけないと配列の先頭の要素だけが解放されるからみたいだ。
参照
特殊なポインタで、自動的に間接参照され、参照先のオブジェクトと同義で使うことが出来る。暗黙のポインタ。関数へ引数を渡すときにポインタを渡す代わりに参照で渡すと、関数の中で通常の変数のように扱うことが出来る。
あるいは関数から値を返すときに参照で渡すことも出来る。
samp &f(samp &x){...}
でsampクラスの参照を渡して、その参照を返す関数になる。
参照とポインタの違い
- 他の参照を参照できない
- 参照のアドレスは取得できない
- 参照の配列を作成できない
- ビットフィールドを参照できない
- クラスのメンバ、戻り値、関数引数以外では、初期化しなければならない。
class test{ int i; public: test(int a){i = a;}; ~test(){cout << "destructer is called";}; }; test_c test_r(test &a){ return a; } int main(){ test a(112); test_re(a); return 0; }
という感じで&付けないで宣言している関数で参照されている変数を返値にしても、参照先の値がコピーされて返されているみたい。
でデストラクタが二回呼ばれた。
参照の返し
class safe_array{ int *p; int raw,column; public: safe_array(int r,int c){ p = new int [r*c]; raw = r; column = c; }; ~safe_array(){ delete p; } int &put(int i,int j); int get(int i,int j); }; int &safe_array::put(int i,int j){ if(i < 0 || i>= raw || j < 0 ||j >= column){ exit(1); } return p[i*raw + column]; } int safe_array::get(int i,int j){ if(i < 0 || i>= raw || j < 0 ||j >= column){ exit(1); } return p[i*raw + column]; } int main(){ safe_array a(3,2); a.put(1,1) = 2; cout << a.get(1,1) << "\n"; a.get(100,100); return 0; }
境界チェック機能付きの二次元配列ですが、参照を返すことで、返された参照に直接値を代入できるという、楽しげな事が出来る。ここだと配列の要素を参照として返すことで、呼び出しもとルーチンで配列に値を代入している。何か便利な気分。
独立参照
int x = 100; int &ref = x; ref = 10;//xに10が代入される
利点は殆ど無いそうだ。
まとめると参照は
- 仮引数参照
- 独立参照
- 返値の参照
の三つがある。