C++ 再入門 その10 生成と消去 インスタンスって何?
ひとつのデータをいろいろな関数で共有して使うときには、そのデータを関数の引き数で渡します。場合によればグローバル変数やファイル単位のstaticな変数を使うことがありますが引き数を使うのが一般的です。単純なデータであればデータをコピーして引き数に渡しますが、複雑なデータであったり内容を書き換えるのであれば、データのポインタを引き数に積みます。
C++でクラスの型を持つ変数を使うときにも同じ話に成ります。構造体の場合を思い出していただければ殆ど変わりません。構造体の変数を使うときも、まず構造体の型を定義し、その型の変数を宣言して使います。クラスも同じでクラスを定義し、クラスの名前を使ってそのクラスの変数を宣言します。クラスの変数を宣言してクラスの実体を作ることを「インスタンスの生成」と呼ぶこともあります。この呼び名はオブジェクト指向の考え方から来ていて、クラスの定義はいわゆる「設計図」で、この設計図をもとに何かを実際に作った時に、これを「インスタンス」と呼ぶのです。
構造体であれば変数を宣言しても、単に領域が確保されるだけで何かの処理が行われるわけではないのですが、クラスの場合には事情が違います。インスタンスを生成する際には、まず、そのクラスの持つ変数の領域を確保してから(もしあれば)コンストラクタを呼び出します。そして変数の有効範囲を抜けると、コード上に何も書いていなくても(もしあれば)デストラクタを呼び出すのです。そのクラスにコンストラクタ(やデストラクタ)が書かれていなくても、クラスが他のクラスから継承されていたり、メンバ変数にクラスがあれば、それらが持っているコンストラクタ(またはデストラクタ)が呼ばれます。
ポイントは宣言をした段階で何らかの処理が行われ、スコープを抜けるときにも見えないところで何らかのコードが走ることがあるという点です。ここが構造体と大きく異なる部分です。それで単に変数と呼ばすにインスタンスと異なる言葉を使っているのですね。
インスタンス
補足しておくと、一般的な関数は引き数に書いてある通りの変数を渡すだけですが、クラスに書かれているクラス関数を呼び出す場合には、引き数に何も書いていなくても、対象となるインスタンスへのポインタ(thisポインタ)も渡しています。これでクラス関数からインスタンスにある変数の値を引き数で渡すこと無く読み書きできるわけです。何だと思うかもしれませんが、ちょっとしたマジックですよね。実は変数や関数の宣言の種類によっては、このポインタが渡らないなんていうこともあって混乱することがあります。C++って何だかんだ複雑ですよね。
C言語であれば、基本的に何らかの処理が行われる場合には必ず対応するコードがあり(型変換などは見えにくいですが)、何も書いていなければそこに処理は無いのですが、C++では何も書いていないのに、見えない処理が走るところが多くあります。これはいちいち細かな処理を明示的に書かなくても複雑な処理を自動的に行なってくれるという素晴らしい機能ではあるのですが、慣れないと(特にコンパイルエラーが出たりバグが出た場合には)見えない部分で何が起こっているかを把握するのが難しくて途方にくれることもママあります。まあコンパイルさえできればデバッガでコードを追うことで理解できるかもしれませんが、そもそもコンパイルできないと見るべきコードが生成されないのが困ったところです。ちゃんとコードが生成できている間に最適化をオフにしたコードを読むのも理解の助けにはなると思います。
さて、そろそろ動的メモリ(ヒープ)の話もしておきますか。
#プログラミング #プログラミング講座 #CPP #インスタンス #コンストラクタ #デストラクタ #this