継承を説明
データを拡張してプログラムを作成することを通して、継承の概念を説明する。
C言語での限界
struct Person { char name[ 10 ] ; int age ; } ; void print( struct Person* p ) { printf( "%s %d\n" , p->name , p->age ) ; } struct Jyoshi { struct Person person ; int size ; // 部下の人数 struct Person* table[ 10 ] ; // 部下へのポインタ } ; void print_jyoshi( struct Jyoshi* p ) { print( &p->person ) ; for( int i = 0 ; i < size ; i++ ) // 本人と部下のデータを表示 print( p->table[ i ] ) ; } void main() { struct Person saitoh ; // 初期化も適度に行うとする struct Jyoshi ashida ; print( &saitoh ) ; // print( &ashida ) ; // saitohと同じ様にprintしたいけど、できない print( &ashida.person ) ; print_jyoshi( &ashida ) ; // 部下の表示が不要だとしたら // わざわざJyoshiバージョンを作るのが面倒。 }
unionを使えば…
union PERSON { // 初期化の処理は省略 struct Person person ; struct Jyoshi jyoshi ; } ;
こういう方法を使えば、jyoshi の先頭部分はpersonであり、 共用体によって、同じ部分に person が配置されている。 こういった共用体を使って、拡張部分のあるデータを同じように扱うテクニックは、 unix のグラフィックシステム X11 に見られる。 例年は、共用体を使うテクニックまでは解説しないけど、 今年度は受講者が電子情報出身者だけになったので、解説を行った。
派生と継承
データを拡張しても同じように扱うテクニックとして、派生があることを説明。 前の例みたいなことは、C++であれば以下のように行う。
class Person { // データの共通部で元になるものを private: // 基底クラスと呼ぶ。 char name[ 10 ] ; int age ; public: Person( char s[] , int a ) { strcpy( name,s ) ; age = a ; } void print() { printf( "%s %d\n" , name , age ) ; } } ; class Jyoshi : public Person { // 派生クラス private: int size ; Person* table[ 10 ] ; public: Jyoshi( char s[] , int a ) : Person( s , a ) // 基底クラスの初期化 { size = 0 ; } void buka( Person* p ) { table[ size++ ] = p ; } } ; void main() { Person saitoh( "saitoh" , 45 ) ; Jyoshi ashida( "ashida" , 60 ) ; ashida.buka( &saitoh ) ; saitoh.print() ; ashida.print() ; // ここがミソ:基底クラスのメソッドを流用 }
最後のJyoshiのデータ ashida において、print メソッドは存在しないが、 基底クラスのprintメソッドを流用してくれる。これを継承と呼ぶ。
void Jyoshi::print() { Person::print() ; for( int i = 0 ; i < size ; i++ ) table[ i ]->print() ; }
上記のような、Jyoshi専用のprintを定義してもいい。