隠蔽化とコンストラクタとgetter,setter
前回までの授業で、簡単なクラスを作るまでを説明したので、 複素数クラスのリファクタリングを通して、隠蔽化を説明。
getter,setterメソッド
前回の授業では、以下のプログラムを示していたが、 例えば名前nameや年齢ageを外部で使用したい場合には、 name,age のprivate設定を、public にする方法が考えられる。
class Person { private: // publicにする? char name[ 20 ] ; int age ; public: void set( char s[] , int a ) { strcpy( name , s ) ; age = a ; } void print() { printf( "%s %d¥n" , name , age ) ; } } ;
しかし、name,age を public にすると、不容易にクラス内の変数を 触られてトラブルの元凶となる場合がある。 こういった場合、フィールドを参照するだけのメソッド(getter), フィールドに値を参照するだけのメソッド(setter)を定義する方法が 有名である。 また、getterメソッドなどは、値を参照するだけで、クラス内に副作用を与えないことを 明示するために、const メソッドを指定することもできる。 setter では、代入時に想定外の値が入力されないように、 開発中だけ、値のチェック処理を埋め込むなどの使い方もできる。
class Person { private: char name[ 20 ] ; int age ; public: // getter const char* get_name() const { return name ; } int get_age() const { return age ; } // setter void set_name( char s[] ) { strcpy( name , s ) ; } void set_age( int a ) { // リリース版ではif文をコメントアウト if ( a < 0 )printf( "set_age(int) : domain error¥n" ) ; age = a ; } } ;
コンストラクタとデストラクタ
最初の例のset() メソッドのように、オブジェクトは何らかの初期化をするのが通常であり、 逆に初期化を忘れたオブジェクトは、後々異常動作の元になる。 このため、データの初期化を簡単に扱えるようにコンストラクタ(構築子)を用いる。
また、データを生成し何らかの処理を行った後、そのデータを廃棄する前に必ず処理を 呼び出したい場合がある。こういった場合にはデストラクタを用いる。
class Person { private: char name[ 20 ] ; int age ; public: // コンストラクタ(データを初期化するメソッド) Person( char s[] , int a ) { strcpy( name , s ) ; age = a ; } // デストラクタ(データを廃棄するときに自動的に呼び出し) ~Person() { printf( "destructor %s,%d¥n" , name , age ) ; } void print() { printf( "%s %d¥n" , name , age ) ; } } ; int main() { Person saitoh( "t-saitoh" , 49 ) ; saitoh.print() ; // saitoh.print() で "t-saitoh 49"が表示され // mainを抜ける際にデストラクタが呼び出され、 // "destructor t-saitoh,49"が表示される return 0 ; }
複素数クラスで隠蔽化とリファクタリング
前述のような、getter,setterによりデータを不用意に扱われないようにする 対策に合わせ、クラス利用者にクラス内の情報を知らなくても扱える(データ構造の隠蔽化)、 そのメソッドがどのように実装されているか知らなくても使える(手続きの隠蔽化)を 行うことを総称して、隠蔽化(あるいはブラックボックス化)と呼ぶ。
隠蔽化を施せば、後で内部構造や内部処理を書き換えても、クラスの利用者には 影響を少なくできることを示すために複素数クラスを考える。 最も一般的な方法であれば、実部と虚部で以下のように実装するだろう。
class Complex { private: double re , im ; public: Complex( double r , double i ) : re( r ) , im( i ) { // 上記は要素を指定値で初期化する場合の書き方。 } void print() { printf( "%lf+j%lf" , re , im ) ; } void add( Complex z ) { re = re + z.re ; im = im + z.im ; } void mul( Complex z ) { double nr = re * z.re - im * z.im ; double ni = im * z.re + re * z.im ; re = nr ; im = ni ; } } ; int main() { Complex a( 1 , 2 ) ; Complex b( 2 , 3 ) ; Complex c( 3 , 4 ) ; a.add( b ) ; // a.add( Complex( 2,3 ) ) ; もアリ a.print() ; // 3+j5 を表示。 a.mul( c ) ; a.print() ; // (3+j5) * (3+j4) return 0 ; }
上記のプログラムでは、add() はシンプルに記述できたけど、 乗算はそれなりに複雑(という程でもないけど…)になった。 しかし、複素数を絶対値と偏角で記述することも可能となる。
class Complex { private: double abs , arg ; public: Complex( double r , double i ) { abs = sqrt( r*r + i*i ) ; arg = atan2( i , r ) ; } void mul( Complex z ) { abs *= z.abs ; arg += z.arg ; } // 他のメソッドは記載省略 } ;
上記の例の様に、当初のクラス設計で不具合があった場合に 後で「内部設計・メソッドを全面変更」を行うと、通常であれば クラス利用者にも影響が大きい。 しかし、内部設計の変更の影響が出ないように、適切なメソッドを 定義しておけば、クラス利用者に内部変更が解らない様にすることができる。 これが、隠蔽化の利点である。
このように、適切な隠蔽化が行われていれば、クラス内の設計変更は 気軽に行えるようになる。 そして、クラス内部の設計変更を積極的に行うことで、プログラムの改善を 行うことはリファクタリングなどと呼ばれる。
IPアドレスの管理スクリプト適用
自宅のサーバで、IPアドレスの管理のスクリプトを書いたので、 早々に職場にも適用。 /etc/dhcp/dhcpd.conf,/etc/hosts,/etc/samba/lmhosts を テンプレート生成するようにしてみた。
hosts,lmhosts は、あまり使われないけど、 ネットワークトラブル時に、この辺の設定があると 対応がしやすいので…
2014年4月27日(第370回)
- まるよし Train Pops ~ 国語と遊ぼう! 第52回 「二人称」
- 動物の話
- 新入生に質問!
初登場:田嶋君(2C)、辻君(1M)
担当:前田勝(5EI)、松島(3C)、稲葉(1EI)、山田(1B)
2014年4月20日(第369回)
- まるよし Train Pops ~ 国語と遊ぼう! 第51回 「学級日誌」
- 新入生に質問!
新入生ゲスト:川崎さん(1EI)、小藤さん(1B)、稲葉さん(1EI)
担当:前田勝(5EI)、山野(3C)、松島(3C)、西(教員)
画像探索(最小二乗法)
創造工学の競技部門向けの予備実験として、簡単な画像探索プログラムの実験を行った。
処理の内容は、大きな元画像の中から、その一部をクリップした部分を検索するプログラムを動かしてもらった。 サンプルでは、全2次元空間をしらみつぶしに探す方法で、極めて遅いプログラムを示し、 改良高速化をしてもらうこととした。
ppm画像の読み込みサンプル
4年当初では、コマンドライン引数やら、画像形式の読み込みなどが理解していないため、 下記の readppm.cxx を示して、ppm画像の読み込み処理と、コマンドライン引数を説明。
画像探索プログラムのサンプル
前記プログラムがわかった所で、画像探索プログラムのサンプルコードを示す。 このプログラムは、1ドット毎に左上から右下まで移動させながら、 画素のRGBのズレの合計スコアの最小の場所を記憶させる手法。
自宅マシンで動かすと、600×400程度の画像の中から、100×100程度の画像を検索するのに、40秒ほどかかる。 実験では、動作確認のあと、処理の高速化をしてもらった。
また、問題が起こりそうな事例ということで、 検索画像が輝度補正がかっている場合(HSVなりYCbCrなりの色空間で比較が必要)や、 ぼけた画像でも正しく動くのか試してもらった。
Googleさんが、緊急メールを迷惑メールに入れた…
子供の中学校から、緊急メールが流れてきたんだけど、 Gmail宛に送ってるけど、迷惑メールに分類されてた。(T_T;
まあ、確認のためのURLの中に、メールアドレスが埋め込んでいるし、 典型的な迷惑メールのスタイルといえばそうなんだけどさぁ…
2014年4月13日(第368回)
- まるよし Train Pops ~ 国語と遊ぼう! 第50回 「元号の漢字」
元号で多く使われている漢字をランキングでご紹介! - 新入生への質問コーナー
放送・メディア研究会の新入生にスタジオで質問
新入生ゲスト:山田君(1B)、森山君(1M)
担当:前田勝(5EI)、山野(3C)、松島(3C)、西(教員)
2014年4月6日(第367回)
- まるよし Train Pops ~ 国語と遊ぼう! 第49回 「元号の漢字」
- 入学式の話
- 新年度の目標
担当:山野(3C)、松島(3C)、西(教員)