先週頃より、電子情報以外の学科の学生さんは、 難しいのか参加しなくなってきた。 5名だけを相手の説明って何だか寂しいなぁ。
先週に説明した、導出の概念をもう一度説明した後、クラスの格下げにより できそうでできない処理の例を説明する。
class Syain { private: char name[10] ; int age ; public: Syain( char s[] , int a ) { strcpy( name , s ) ; age( a ) ; } void print() { printf( "%s %d" , name , age ) ; } } ; class Jyoshi : public Syain { private: Syain *buka[10] ; int size ; public: Jyoshi( char s[] , int a ) : Syain( s , a ) { size = 0 ; } } ; int main() { Syain a( "ひら1" , 24 ) ; Syain b( "ひら2" , 27 ) ; a.print() ; Jyoshi c( "部長" , 43 ) ; c.print() ; // 継承により、OK Jyoshi d( "社長" , 59 ) ; c.add( &a ) ; c.add( &b ) ; // cの部下の追加 d.add( &c ) ; // c は Syain に格下げされて追加された。 Syain e( "ひら3" , 33 ) ; d.buka[0]->add( &e ) ; // ☆NG: buka[0] は c:Jyoshi だけど、 return 0 ; // 格下げされているので add を実行できない。 }
上記の例の解決策の方向性として、仮想関数の話しを行う。 最初に、C 言語の共有体(union)を用いて、1つの配列に異なる型を入れるテクニック を紹介し、型識別番号と分岐処理の手間を説明する。 この問題の解決策として以下のような仮想関数を利用した事例を紹介。
class Data { public: virtual void print() = 0 ; } ; class Int : public Data { private: int x ; public: Int( int a ) : x( a ) {} virtual void print() { printf( "%d" , x ) ; } } ; class Double : public Data { private: double y ; public: Double( double a ) : y( a ) {} virtual void print() { printf( "%f" , y ) ; } } ; class String : public Data { private: char s[ 10 ] ; public: String( char*a ) { strcpy( s , a ) ; } virtual void print() { printf( "%s" , s ) ; } } ; int main() { Int a( 123 ) ; Double b( 1.234 ) ; String c( "ABC" ) ; Data* array[3] ; array[0] = &a ; // 仮想関数でなければ、クラスの格下げが発生している array[1] = &b ; array[2] = &c ; for( int i = 0 ; i < 3 ; i++ ) // 仮想関数の呼び出し array[i]->print() ; // 異なる型が混ざった配列でも OK return 0 ; }
仮想関数と継承の考え方の応用事例として、コンテナクラスなどの便利な機能が 実現できることや、C++ では template によるコンテナクラスの事例が多いので、 以下の template 文の事例を紹介する。
template swap( T* a , T* b ) { T c = *a ; *a = *b ; *b = c ; } void main() { int a = 123 , b = 234 ; float c = 1.234 , d = 2.345 ; swap( &a , &b ) ; swap( &c , &d ) ; }