ホーム » スタッフ » 斉藤徹 » 継承と仮想関数

2010年6月
« 5月   7月 »
 12345
6789101112
13141516171819
20212223242526
27282930  

最近の投稿(電子情報)

アーカイブ

カテゴリー

継承と仮想関数

先週は、派生・継承について説明を行ったが、今日はその続き。

void main() {
Person saitoh( "saitoh" , 45 ) ;
Jyoshi ashida( "ashida" , 60 ) ;
ashida.buka( &saitoh ) ;
Person* list[2] ;
list[0] = &saitoh ;
list[1] = &ashida ;
for( int i = 0 ; i < 2 ; i++ )
list[ i ]->print() ;
}

この例では、list[1]=&ashida ができることが注目点。 派生クラスのポインタは、基底クラスのポインタに格下げが許される。 この例であれば、list[1]->print() では、list[1]=&ashida とする時点で、 Jyoshi型がPerson型になっているため、Person型のprint()が実行され、 部下の情報は表示されない。

しかし、実際のプログラムでは、list[1]->print() にて、Jyoshi::print() が呼び出して 欲しい場合も多い。こういった場合には、仮想関数を用いる。 virtual 宣言されたメソッドが宣言されると、データ構造の構築時に、 型情報を覚えるためのID(型情報)も保存される。 また、仮想関数の呼び出しでは、型情報に応じてメソッドが呼び出される。

class Person {
:
public:
virtual void print() {
printf( "%s %d\n" , name , age ) ;
}
} ;
class Jyoshi : public Person {
private:
int size ;
Person* table[ 5 ] ;
public:
virtual void print() {
Person::print() ;
for( int i = 0 ; i < size ; i++ )
table[i]->print() ;
}
} ;

パソコンでプログラムを打ち込みながら、受講している人がいたので、 Person型のサイズsizeof( Person )を確認すると、 virtual 宣言した場合、データサイズが4byte拡大することが確認できた。 実際には、型情報として「仮想関数の関数ポインタ配列へのポインタ」が 使われることが多いので、そのポインタ分の4byte増加と思われる。

int main(int argc,char**argv)

Cの授業でも、間違いとは説明するものの"void main(){}" でプログラムを書いていたり するけれど、C++だと明確にエラーになるため、argc,argvも含めて解説する。

int main( int argc , char*argv[] ) {
for( int i = 0 ; i < argc ; i++ )
printf( "%s\n" , argv[i] ) ;
// プログラムを a.out Hello World と実行すれば、
// argv[0]=a.out,argv[1]=Hello,argv[2]=World になる。
return 0 ; // mainの正常終了(プロセスのリターン値でOSに渡される)
}

new delete

上記の仮想関数のプログラム例は、実プログラムでは、 以下のようなコードでインスタンスを生成する場合も多い。

Person *saitoh = new Person( "斉藤" , 45 ) ;

と簡単に説明しようとしたら、new,delete の説明をしてなかった。 new, delete は動的にメモリを確保するC言語のmalloc,freeに相当する演算子。

// C言語の場合
int *p ;
if ( (p = (int*)malloc( sizeof(int) * 100 ) != NULL ) {
// p[i] を整数配列として使える
free( p ) ;
}
// C++のnew,deleteの場合
int *p = new int[ 100 ] ;
// new演算子はメモリ確保の失敗には例外を使うので
// NULLチェックは不要。
// p[i]を整数配列として使える
delete [] p ;
// Personの例で説明
Person* p = new Person( "斉藤" , 45 ) ;
// new Personでは、コンストラクタも実行される。
p->print() ;
delete p ;
// delete では、デストラクタ呼び出しも行われる。