// ( r17.C ) // クラスの暗黙の定義 // #include #include class String { char* str ; public: String( void ) { str = NULL ; } String( char* p ) { str = new char[strlen(p)+1] ; strcpy( str,p ) ; } ~String() { strcpy( str,"----" ) ; // str=NULL では show() すると文字列がでてしまう delete str ; cout << "del String\n" ; } void show() { cout << str << "\n" ; } //----------------------------------------------------------------------------- どんなクラスでもクラスを定義すると、自動的にコピ−コンストラクタとオペレ−タ= がそのクラスに付加される。String クラスに関しては以下のような定義が追加される。 String( const String& p ) { str = p.str ; } const String& operator=( const String& p ) { str = p.str ; return *this ; } 注意することは自動的に定義されるこれらは、インスタンスのコピ−を行うものである が、単なるデッドコピ−をするに過ぎない。コピ−する中味がこの例題のようにポイン タ(char* str)である場合、同じ変数を差し示すことになり、問題が生じる場合がある。 コピ−する中味がただの変数、例えば(char str)の場合は、暗黙に定義されるもので何 ら問題はない。 しかし普通クラスのメンバ変数にポインタを設けるのは、例えば Line クラスに Point クラスのポインタを持つような場合で、Point の実体が消えた時は Line の方の Point も当然消えていることが望まれる。このためこの例題のようなケ−スは稀だと考えられ る。可変長の文字列を定義するために、ポインタを用いたことが問題の元になっている。 //----------------------------------------------------------------------------- // 暗黙の定義に対し、問題が起こらないように次の2つをオ−バライド定義する。 String( const String& p ) { // 特にコピ−コンストラクタと言う str = new char[strlen(p.str)+1] ; strcpy( str,p.str ) ; // [実験] cout << "copy make String\n" ; // この2つの実装をコメントにしたり } // 外したりして、実行してみること。 String& operator=( const String& p ) { str = new char[strlen(p.str)+1] ; strcpy( str,p.str ) ; cout << "= make String\n" ; return *this ; } } ; main() { String a("katou"); if (1) { String b = a ; // copy make String, String b(a); でも同じ結果になる } // del String, インスタンス b のデストラクタが働く a.show() ; String c ; if (1) { String d("haruo") ; c = d ; // = make String } // del String, インスタンス d のデストラクタが働く c.show() ; }