プログラミングII 第 7 回 オブジェクトの配列 New, delete 参照 田向 単項演算子 * 2項演算子: x op y ; 単項演算子: op z ; ポインター 宣言 での * とは違う. 変数宣言時では ポインター型の変 数である事を宣言している. → 代入演算の時に,コンパイラが 型チェックをするのに使用する. Int* p; 単項演算子 * は ポインタ変数 の値から アドレスを取り出して,値 取り出しの処理(アドレス・レジスタ にアドレスを書き込む)を行う. x = *p; 単項演算子 & 単項演算子 * と同じように,アドレ ス操作の 単項演算子 & がある. 単項演算子 & は 変数,オブジェ クトのアドレスを取り出す演算. myclass * mp ; myclass myObj ; mp = &myObj ; int x; int * p , q; p= q; x=*p; オブジェクトのアドレス ポインタ変数 – 対象(オブジェクト,変数)の アドレスを値として持つ変数 – オブジェクトの先頭アドレスを値として 持つ – コンパイラはオブジェクト名から先頭ア ドレスを取り出すことが出来る s1 strtype * sp1; sp1= &s1; ベースアドレス f IE L D N A M E 1 f IE L D N E M E 2 オブジェクトのアドレス渡し ポインター変数で渡す クラス名 * ポインター変数名; で定義する. – オブジェクトが存在している場所 を教える. • オブジェクトの先頭のアドレス • オブジェクトはコピーしない – どんなに大きくても先頭アドレスだけが コピーされる – オブジェクトのアドレスは 単項演算子 & で取り出せる • &で取り出した値はアドレスである のでポインタ変数にしまう. • アドレスにも型があるとエラーチェッ クができる Objectのアドレス渡し #include <iostream> using namespace std; class samp { int i; public: samp(int n) { i = n; } void set_i(int n) { i = n; } int get_i() { return i; } }; void sqr_it(samp *o){ o->set_i(o->get_i() * o->get_i()); cout << "iのコピーの値は " << o->get_i(); cout << "\n"; } int main(){ samp a(10); sqr_it(&a); cout << "今、main()は変更された: "; cout << a.get_i(); return 0; } オブジェクトの配列 #include <iostream> using namespace std; class samp { int a; public: void set_a(int n) { a = n; } int get_a() { return a; } }; int main(){ samp ob[4]; //普通に宣言できる int i; for(i=0; i<4; i++) ob[i].set_a(i); for(i=0; i<4; i++) cout << ob[i].get_a( ); cout << "\n"; return 0; } 初期値の設定も同時に出来る #include <iostream> using namespace std; class samp { int a; public: samp(int n) { a = n; } int get_a() { return a; } }; int main(){ samp ob[4] = { -1, -2, -3, -4 }; int i; for(i=0; i<4; i++) cout << ob[i].get_a() << ' '; cout << "\n"; return 0; } 2次元配列も容易 #include <iostream> using namespace std; class samp { int a; public: samp(int n) { a = n; } int get_a() { return a; } }; int main(){ samp ob[4][2] = { 1, 2, 3, 4, 5, 6, 7, 8 int i; for(i=0; i<4; i++) { cout << ob[i][0].get_a() << ' '; cout << ob[i][1].get_a() << "\n"; } cout << "\n"; return 0; } }; コンストラクタを使った初期化 #include <iostream> using namespace std; class samp { int a, b; public: samp(int n, int m) { a = n; b = m; } int get_a() { return a; } int get_b() { return b; } }; int main(){ samp ob[4][2] = { samp(1, 2), samp(3, 4), samp(5, 6), samp(7, 8), samp(9, 10), samp(11, 12), samp(13, 14), samp(15, 16) }; int i; for(i=0; i<4; i++) { cout << ob[i][0].get_a() << ' '; "\n"; cout << ob[i][1].get_a() << ' '; "\n"; } cout << "\n"; return 0; } cout << ob[i][0].get_b() << cout << ob[i][1].get_b() << オブジェクトのポインタ #include <iostream> using namespace std; class samp { int a, b; public: samp(int n, int m) { a = n; b = m; }; int get_a() { return a; }; int get_b() { return b; }; }; int main(){ samp ob[4] = { samp(1, 2), samp(5, 6), samp(3, 4), samp(7, 8) }; samp * p; p = ob; // 配列の開始アドレスを取得する int i; p ->a = (*p).a cout << p -> get_a( ) << ' '; cout << p -> get_b( ) << "\n"; for(i=0; i<4; i++) { p++; // // 次のオブジェクトに進む } cout << "\n"; return 0; } 練習 次のクラスを使用して,2行5列の2 次元配列を作成し,配列内の各オ ブジェクトに任意の初期値を設定し なさい.次に,配列の内容をポイン タを用いて表示しなさい. class a_type { double a, b; public: a_type(double x, double y){ a = x; b = y; } void show(){ cout << a << ‘ ‘ << b << “\n”; } }; this pointer #include <iostream> #include <cstring> using namespace std; class inventory { char item [20]; double cost; int on_hand; public: inventory(char * i, double c, int o) { strcpy(item, i); cost = c; on_hand = o; } void show(); }; void inventory::show(){ cout << item; cout << ": $" << cout << " 在庫: " << on_hand << "\n"; } int main(){ inventory ob("レンチ", 4.95, 4); ob.show(); return 0; } cost; this pointer 明示して記述 #include <iostream> #include <cstring> using namespace std; class inventory { char item[20]; double cost; int on_hand; public: inventory(char *i, double c, int o) { strcpy(this -> item, i); // thisポインタを this -> cost = c; // 使用してメンバに this -> on_hand = o; // アクセスする } void show(); }; void inventory::show(){ cout << this ->item; // thisポインタを使用してメ ンバにアクセスする cout << ": $" << this ->cost; cout <<" 在庫:"<< this ->on_hand<<"\n";} int main(){ 4); inventory ob("レンチ", 4.95, ob.show(); return 0; } New ,delete 演算子 #include <iostream> using namespace std; int main(){ int *p; p = new int; // 整数のメモリを確保・割り当てる if(!p) { cout << "メモリ割り当てエラー\n"; return 1; } *p = 1000; cout << "pが指している整数型は: " << *p << "\n"; delete p; // メモリを解放する return 0; } mallocにかわる. heap 領域に領域を確保 する. 動的オブジェクトを割り当てる #include <iostream> using namespace std; class samp { int i, j; public: void set_ij(int a, int b) { i=a; j=b; } int get_product() { return i*j; } }; int main(){ samp *p; p = new samp; // new で オブジェクトを割り当てる if(!p) { cout << "メモリ割り当てエラー\n"; return 1; } p->set_ij(4, 5); cout << "積は: " << p->get_product() << "\n"; return 0; } 動的オブジェクトを割り当てる #include <iostream> using namespace std; class samp { int i, j; public: samp(int a, int b) { i=a; j=b; } int get_product() { return i*j; } }; int main(){ samp *p; // オブジェクトを割り当てて初期化する p = new samp(6, 5); if(!p) { cout << "メモリ割り当てエラー\n"; return 1; } cout<<"積は: "<< p->get_product()<<"\n"; delete p; return 0; } 配列のnew, delete #include <iostream> using namespace std; int main(){ int *p; // 5つの整数用のメモリを割り当てる p = new int [5]; // 割り当てが成功したことを常に確認する if(!p) { cout << "メモリ割り当てエラー\n"; return 1; } int i; for(i=0; i<5; i++) p[i] = i; for(i=0; i<5; i++) { cout << "整数型p[" << i << "]は: "; cout << p[i] << "\n"; } delete [ ] p; // メモリを解放する return 0; } オブジェクト配列でのnew,delete #include <iostream> using namespace std; class samp { int i, j; public: void set_ij(int a, int b) { i=a; j=b; } ~samp() { cout << "デストラクタ呼び出し\n"; } int get_product() { return i*j; } }; int main(){ samp *p; int i; p= new samp [10]; // オブジェクト配列を割り当てる if(!p) { cout << "メモリ割り当てエラー\n"; return 1; } for(i=0; i<10; i++) p[i].set_ij(i, i); for(i=0; i<10; i++) { cout << "積 [" << i << "] は: "; cout << p[i].get_product() << "\n"; } delete [] p; return 0; } 参照(reference)&変数 変数の別名(alias)として動作する 用途 1. 関数の引数として参照を渡す. 2. 関数から参照を返す. 3. 独立した参照(非推奨) 効果 1. 関数間でオブジェクトを渡す際, コピーが発生しないため,巨大 なオブジェクトを取り扱うプログ ラムを高速処理可能 2. 左辺で関数が呼べる 3. コピーコンストラクタ,演算子の オーバーロードで利用される. ポインタ仮引数を使用する場合 #include <iostream> using namespace std; void f(int *n); // ポインタ仮引数を宣言する int main(){ int i = 0; f(&i); // i のアドレスを取り出す&演算 cout << "iの新しい値: " << i << '\n'; return 0; } void f(int *pn){ *pn = 100; // nが指す引数に100を格納する } *演算子: ポインタ変数 pn の値=オブ ジェクトiのアドレスの場所を取り出す. = 取り出したアドレスの処に100を置く. 参照仮引数を使用する場合 #include <iostream> using namespace std; void f(int &n); // 参照仮引数を宣言する int main(){ int i = 0; f(i); cout << "iの新しい値: " << i << '\n'; return 0; } // f( )関数は参照仮引数 & を使用する void f(int &n) { // int &n = i; と同じ意味 // 次の文では * が必要ない *n=100 // n は i の別名である n = 100; // f()関数を呼び出すのに使用し た引数nに100を格納する } 参照の例-I #include <iostream> using namespace std; void swapargs(int &x, int &y); int main(){ int i, j; i = 10; j = 19; cout << "i: " << i << ", "; cout << "j: " << j << "\n"; swapargs(i, j); cout << "交換後: "; cout << "i: " << i << ", "; cout << "j: " << j << "\n"; void swapargs(int &x, int &y){ int t; t = x; x = y; y = t; } x , y はi, j の別名なので, i, jの値が交換される. return 0; } 参照の例-II #include <iostream> using namespace std; class myclass { int who; public: myclass(int n) { who = n; cout<<"コンストラクタ呼び出し"<<who<< "\n"; } ~myclass() { cout << "デストラクタ呼び出し " << who << "\n"; } int id( ) { return who; } }; void f(myclass &o){ // oを参照によって渡す // .演算子を使用していることに注意 cout << "受け取り " << o.id() << "\n"; } int main(){ myclass x(1); f(x); //fでXはコピーされない.fを抜ける時に //デストラクタ ~myclass は呼ばれない return 0; } 参照を返す関数の効能-I #include <iostream> #include <cstdlib> using namespace std; class array { int size; char *p; public: array(int num); ~array() { delete [] p; } char &put(int i); char get(int i); }; array::array(int num){ p = new char [num]; size = num; } char &array::put(int i){// 配列に情報を格納する return p[i]; // p[i]への参照を返す } 参照を返す関数の効能-II // Get something from the array. char array::get(int i){ return p[i]; // 文字を返す } int main(){ array a(10); //左辺で関数が呼べる.普通の関数では不可 // 戻り値がアドレスだから出来る. a.put(3) = ‘X’; a.put(2) = ‘R’; cout << a.get(3) << a.get(2); cout << "\n"; return 0; } 独立参照 #include <iostream> using namespace std; int main() { int x; int &ref = x; // 独立参照を作成する x = 10; ref = 10; // この2つの文の // 機能は同等である ref = 100; // 100を2回出力する cout << x << ' ' << ref << "\n"; return 0; } refはxの別名である. 使用さえる事は少ない. 練習 次のプロトタイプ宣言を利用して, orderで指定された桁数までnumの 桁数を上げるmag()という関数を作 成せよ. 例えば,num = 4, order = 2 のとき, 関数 mag() が終了したとき num = 400 になるようにせよ. void mag(long &num, long order); まとめ:オブジェクトは物 • 物objectの情報classは存在する. 抽象classから具体化classの流れ (派生). 物には内部構造(メンバー)がある. 物objectの中には物objectsがある. 物の中では物が同じように相互に関 係している. – Classという情報として存在している. • 画像,音,物理的,数学的,情報的に存 在するものは物: オブジェクトである. • Windows, AV関連プログラムは物を扱う. • 処理(プログラム)も物としてやり取りする. Applet (application + let(小さい)) • 回路も物,HDL,LSI回路,仮想回路 WindowsもCRT画面内の物 myWindow-1 myWindow-3 myWindow-2 progII > myWindows::windows(…){…} Rootはwindow OSでCRT全体. すべてのwindowは,window OSにつながっている. Windos OSにメッセージを送って,それぞれの window オブジェクトに対して処理を行う. Turbo C++によるアプリ例 • フリーのIDEであるTurbo C++を 利用したアプリの作成例を紹介 する. • Windows アプリの基本的部品 である,Windowやボタン,画像 格納領域等は全て開発環境内 に準備されているクラスからオ ブジェクトを生成して利用する. • 上記クラスの具体的な実装方 法は知る必要が無い. • 上記クラスの利用方法,すなわ ちメンバ変数やメンバ関数,継 承関係などはヘルプやWEBで 検索可能.
© Copyright 2025 ExpyDoc