インタラクティブ・ゲーム制作 <プログラミングコース>

Slides:



Advertisements
Similar presentations
Item 1:View C++ as a federation of languages. C++ はただの ”C のクラスがあるバージョン ” ではない → 例外安全 (29 項 ) 、テンプレート (41 項 ) 、オーバーロード等の導入によりデザインや目指すコードが 変化している プログラミング言語はあくまで言語.
Advertisements

C 言語講座第 5 回 構造体. 構造体とは ... 異なる型の値をまとめて新しい型とする 機能がある . つまり , 複数の変数を 1 つのまとまりにできる . 配列と違って同じ型でデータをまとめるのではな く違った型のデータをまとめられる .
ISD実習E 2009年6月29日 LISPシステム入門 (第5回) 関数ポインタ eval システム関数.
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
1.1 C/C++言語 Hello.ccを作りコンパイルしてa.outを作り出し実行する
数理情報工学演習第一C プログラミング演習 (第3回 ) 2014/04/21
~手続き指向からオブジェクト指向へ(Ⅰ)~
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
アルゴリズムとプログラミング (Algorithms and Programming)
基礎プログラミングおよび演習 第9回
C言語講座 第4回 ポインタ.
プロジェクト演習III,V <インタラクティブ・ゲーム制作> プログラミングコース
第6章 2重ループ&配列 2重ループと配列をやります.
構造体.
インタラクティブ・ゲーム制作 <プログラミングコース>
プログラミングII 第 7 回 オブジェクトの配列 New, delete 参照 田向.
インタラクティブ・ゲーム制作 <プログラミングコース>
補足説明.
細かい粒度でコードの再利用を可能とするメソッド内メソッドのJava言語への導入
プログラミング2 関数
情報工学演習I 第12回 C++の演習4(インライン展開).
関数の定義.
ローカル変数とグローバル変数 ローカル変数  定義された関数内だけで使用できる変数 グローバル変数 プログラム全体で使用できる変数.
Cプログラミング演習 第7回 メモリ内でのデータの配置.
2005年度 データ構造とアルゴリズム 第3回 「C言語の復習:再帰的データ構造」
第10章 これはかなり大変な事項!! ~ポインタ~
第7回 プログラミングⅡ 第7回
復習 前回の関数のまとめ(1) 関数はmain()関数または他の関数から呼び出されて実行される.
プログラミング言語論 第五回 理工学部 情報システム工学科 新田直也.
アルゴリズムとデータ構造 補足資料5-1 「メモリとポインタ」
第11回 プログラミングⅡ 第11回
P n ポインタの基礎 5 q m 5 7 int* p; int 型の変数を指すポインタ int* q; int 型の変数を指すポインタ int n=5, m=7; int 型の変数 int array[3]; int* pArray[3]; p = &n; ポインタにアドレスを代入しているのでOK.
オブジェクト指向言語論 第八回 知能情報学部 新田直也.
一時的な型 長谷川啓
プロジェクト演習III,V <インタラクティブ・ゲーム制作> プログラミングコース
オブジェクト・プログラミング 第8回.
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
アルゴリズムとプログラミング (Algorithms and Programming)
プログラミング 3 2 次元配列.
プログラミング言語論 第十一回 理工学部 情報システム工学科 新田直也.
C#プログラミング実習 第3回.
ポインタとポインタを用いた関数定義.
計算機プログラミングI 木曜日 1時限・5時限 担当: 増原英彦 第1回 2002年10月10日(木)
情報基礎演習B 後半第2回 担当 岩村 TA 谷本君.
アルゴリズムとデータ構造1 2009年6月15日
第5回 プログラミングⅡ 第5回
オブジェクト指向言語論 第五回 知能情報学部 新田直也.
JAVA入門⑥ クラスとインスタンス.
オブジェクト指向言語論 第九回 知能情報学部 新田直也.
cp-2. 属性,アクセサ (C++ オブジェクト指向プログラミング入門)
アルゴリズムとデータ構造 2010年6月17日
フレンド関数とフレンド演算子.
演算子のオーバーロード.
プログラミング演習I 2003年6月11日(第9回) 木村巌.
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
情報処理Ⅱ 2005年11月25日(金).
プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
プログラミング演習II 2004年11月 2日(第3回) 理学部数学科・木村巌.
プログラミング入門2 第5回 配列 変数宣言、初期化について
プロジェクト演習III,V <インタラクティブ・ゲーム制作> プログラミングコース
プロジェクト演習III,V <インタラクティブ・ゲーム制作> プログラミングコース
情報処理Ⅱ 小テスト 2005年2月1日(火).
値渡しと参照渡しについて.
オブジェクト指向言語論 第九回 知能情報学部 新田直也.
C言語講座第5回 2017 構造体.
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
プログラミング 3 ポインタ(1).
計算機プログラミングI 第2回 2002年10月17日(木) 履習登録 複習 ライブラリの利用 (2.6-7) 式・値・代入 (2.6-8)
計算機プログラミングI 第10回 2002年12月19日(木) メソッドの再定義と動的結合 クイズ メソッドの再定義 (オーバーライド)
プログラミング 2 静的変数.
Presentation transcript:

インタラクティブ・ゲーム制作 <プログラミングコース> 第4回 スコープ・ポインタ・参照

今日の内容 スコープの話 ポインタと参照 変数の寿命について コンストラクタと デストラクタの確認 クラスのスコープ ポインタとは何ぞや 参照とは何ぞや うまいお付き合いの 仕方

変数やオブジェクトの寿命の話 スコープ

スコープとは スコープはブロックで決まる 変数やオブジェクトの 有効範囲のこと {}で囲われた範囲を 「ブロック」と呼ぶ 右の例だとwhileループのブロック内に、条件分岐で更に3つブロックがある もちろんwhileループの 外側にも関数のブロックがある スコープはブロックで決まる while(window.update() == true) {   if(キーが押されてたら?) {     うごけー   } else {     押されてなかったら     これやっとけー(省略可)   }   if(違うキーが押されてたら?) {     違う感じにうごけー }

変数が生まれる時・死ぬ時 処理がスコープに 入って宣言された時、 変数が生成される 処理がスコープから 抜ける時、 変数は破壊される 関数呼び出しで一時的に ジャンプする時は大丈夫 今処理している スコープから見えない変数は使えない コンパイルエラーになる void func(void) { // ここで変数hogeが作られる int hoge = 0; if(適当な条件式) { // ここで変数hogehogeが作られる int hogehoge = 0; } // ここで変数hogehogeが破壊される return; // ここで変数hogeが破壊される

じゃあ こう書くしかないじゃない!! int main(int argc, char *argv[]) { /* 凄まじい分量の変数宣言 */ 殺人的な分量の初期化処理 // メインループ while(true) { 目を覆いたくなるようなゲーム処理 } // ここに至るまでに数万行 return 0;

なんでああなるのか? 関数やクラスを覚えても、 うまく使えずこう書く人は多い スコープの問題を解決できないから 今日取り扱う、ポインタや参照を 理解すれば、こんなことはしなくて済む 絶対にやめよう

スコープイン・アウトに 際する重要イベント 変数の場合は、 単純に箱が確保され、消滅するだけ クラスオブジェクトは、イン・アウトで次の関数が呼ばれる スコープインで コンストラクタ スコープアウトで デストラクタ #ifndef __SCOPR_CHECKER_H__ #define __SCOPR_CHECKER_H__ #include <iostream> // スコープの出入り時にメッセージを出すクラス class ScopeChecker { public: ScopeChecker(void) { std::cout << "こうして俺はこの世界に生まれた。" << std::endl; }; ~ScopeChecker() std::cout << "そして俺は世界から抹殺された。" << std::endl; #endif

初期化と後片付け以外にも 色々使い道がある 自動で呼んでくれるという構造を利用して、闇の魔術を行使するC++erも多い ScopeCheckerは その一例 コンストラクタに 引数を取ることで、 実体生成時に名前を付けるようにした→ // さっきのクラスのコンストラクタを改造 // ※一部省略 class ScopeChecker { private: std::string name; public: ScopeChecker(std::string argName) : name(argName) { std::cout << “俺の名は” << name << “……たった今生まれたところさ。” << std::endl; }; // デストラクタも同じように改造しよう

トピック:初期化子リスト コンストラクタで、 メンバ変数に値をセットする最速で確実なやり方 引数リストの後ろに 「: メンバ名(値)」 複数ある時はカンマ区切りで並べる : hoge(1), fuge(2) [上級] 継承している場合は、 親クラスのコンストラクタに引数を渡す時にも使う ScopeChecker(std::string argName) : name(argName) { } // 次のように書いても同じ ScopeChecker(std::string argName) name = argName; // できるだけ初期化子リストを使おう

クラス内のスコープって どうなってるの? お品書きと中身を 分けずに、まとめて書いた状態で考えると分かりやすい クラスという枠で 括られているので、メンバ関数からは メンバ変数が見える class HogeHoge { private: // メンバ変数はクラス内スコープ std::string name; public: HogeHoge() { // スコープ内だからメンバ変数が見える name = “ほげ~”; }; void func() // メンバだから、見えま~す std::cout << name << std::endl;

でもまとめて書くとしんどいので お品書きと本体に 分離して書く 本体を書く時は 「クラス名::関数名」 と書くことで、 「ここだけ一時的にクラスの中だよ!」ということを示す class HogeHoge { // 省略 // 関数の名前・返値の型・引数だけ書く void func(); }; // CPP側では #include “HogeHoge.h” // ここだけHogeHogeの中ってことにして! void HogeHoge::func() { // 飛び地だけど、メンバだから見えま~す std::cout << name << std::endl; }

クラスが見えてるか? オブジェクトが見えているか? クラスを利用するには、クラスの宣言が スコープ内に見えてないとダメ なのでcppの冒頭でincludeする 作ったオブジェクトを操作出来るのは、オブジェクトを作ったスコープ内だけ // HogeHogeクラスを使いたい #include “HogeHoge.h” void func() { // これはOK HogeHoge hoge; hoge.func(); } void funcOther() // hogeは飽くまでfunc()で作ったから // これはNG

ここまでのまとめ ブロック{}によってスコープが決まる スコープに出入りする時、 クラスオブジェクトならコンストラクタとデストラクタが走る クラスのメンバは、クラススコープという括りで括られていると考える

怖くない、ほら、怖くない ポインタと参照

画像を友達に送りたい どんなやり方が考えられるだろうか? 「画像を直接転送する」 「画像をアップロードしてURLを教える」 他にもやり方があるが、それぞれメリットと デメリットがある ポインタは後者の考え方に基づく

現物渡しとURL渡しの違い 現物の場合 URLの場合 転送に時間がかかる お互いそれぞれ手元にファイルが残る コピーしたことになる 送り先の相手が その画像をいじっても、 送り主には影響なし その逆もまた同じ URLの場合 転送は一瞬 送り先の相手は手元に コピーしなくても、URLから画像を見れる コピーすることも可 送り主が画像を 消したり、内容を 変更したら送り先も 影響を受ける 重要

全ての変数にはアドレスがある 変数名に&を付けると、 アドレスになる アドレスは 「ポインタ変数」に しまうことができる ポインタは 「型名 *ポインタ名;」 で宣言する ポインタ変数に*を 付けると、 その中身を取り出せる // main()の中だとして // 適当に作った変数のアドレスを見るコード int hoge = 0; int *pHoge = NULL; pHoge = &hoge; std::cout << pHoge << std::endl; std::cout << *pHoge << std::endl;

関数の引数で利用してみる 関数の定義 呼び出し側 // 渡されてきた値を2倍しようとする関数 void cantChangeValue(int arg_num) { arg_num *= 2; return; } // 渡されてきた値を2倍する関数 void changeValue(int *arg_pNum) *arg_pNum *= 2; // main()の中だとして int num = 10; cout << “before:” << num << endl; cantChangeValue(num); //changeValue(&num); cout << “after:” << num << endl; // 呼び出す側を切り替えて試してみよう

何が違うのか? コピー先をいじっても意味が無い arg_num num 10 10 コピー 20 // 渡されてきた値を2倍しようとする関数 void cantChangeValue(int arg_num) { arg_num *= 2; return; } // main()の中だとして int num = 10; cout << “before:” << num << endl; cantChangeValue(num); cout << “after:” << num << endl; 10 arg_num 10 コピー num 20

何が違うのか? ポインタを通じて元の変数がいじれる num 10 point! 10 arg_pNum アドレスを渡す 20 20 // 渡されてきた値を2倍する関数 void changeValue(int *arg_pNum) { *arg_pNum *= 2; return; } // main()の中だとして int num = 10; cout << “before:” << num << endl; changeValue(&num); cout << “after:” << num << endl; 10 arg_pNum point! 10 アドレスを渡す num 20 20

参照はポインタの簡易版 関数の引数リスト側で&を付けて宣言 関数の呼び出し側は、実体を渡せばよい 後から指し示す対象を変えることはできない 実体と同様に扱える メリットでもあり、 デメリットでもある // 渡されてきた値を2倍する関数(参照版) void changeRefValue(int &arg_pNum) { arg_pNum *= 2; return; } // main()の中だとして int num = 10; cout << “before:” << num << endl; changeRefValue(num); cout << “after:” << num << endl;

実体・ポインタ・参照の違い 関数の引数として使う場合、オブジェクトは実体渡しだと不都合が生じる場合が多い 宣言の仕方 Hoge hoge; Hoge *a; Hoge &a = other; 種類 実体 ポインタ 参照 代入できるもの 実体・定数 アドレス 実体を宣言時に 必ず代入 メンバアクセス .(ピリオド) ->(アロー演算子) &を付けると アドレスになる ポインタの *を付けると エラーになる 実体が取れる 関数の引数として使う場合、オブジェクトは実体渡しだと不都合が生じる場合が多い 読み出し専用は参照、いじくる場合はポインタ、という使い分けをすることが多い

ポインタだからできること newとdeleteの使用 1つのポインタ変数が状況によって指す 対象を切り替えることができる スコープに左右されずに確保したいメモリやオブジェクトを宣言できる 大きなサイズの配列など ポリモフィズムを利用したオブジェクト生成 1つのポインタ変数が状況によって指す 対象を切り替えることができる 最初はとりあえずNULLにしておくことも可能

newとdelete 片付けるには delete アドレス;とする うかつなdeleteは死を招く 実体ができた場所の アドレスが得られるので、ポインタ型の変数で 捕まえて利用する newしたものは 基本的に自分で 片付けねばならない 片付けるには delete アドレス;とする 配列を作った場合にはdelete [] アドレス;とする うかつなdeleteは死を招く まだ利用しているものをdelete したりとか かといってdelete しないでいると、 プログラムが、OSが、死ぬ

まとめ ポインタはエロ画像のURLである ポインタ(参照)を使えば、スコープの枠を飛び越えて変数やオブジェクトを扱える 参照はその簡易版である ポインタ(参照)を使えば、スコープの枠を飛び越えて変数やオブジェクトを扱える

今日の課題 2変数の中身を入れ替える関数を作ろう 期限は来週の授業開始時まで ポインタ・参照どちらでもよい 入れ替えるのはint型かdouble型とする それぞれのバージョンを作るとなおよし 期限は来週の授業開始時まで 超絶楽勝だから今回は期限厳守で!

To be continued…