クラスの基本_オブジェクトとポインタ、コンストラクタ、オーバーライド、仮想関数
仮想関数を把握する前に、クラスのオブジェクトとポインタの違いについて確認した。
【プログラム】
#include <iostream> #include <string> using namespace std; class Base { public: Base(){ cout << "基本クラスのコンストラクタです" << endl; } void func(){ cout << "基本クラスのfunc関数です" << endl; } virtual void func2(){ cout << "基本クラスのfunc2関数です" << endl; } }; class Derive : public Base { public: Derive(){ cout << "派生クラスのコンストラクタです" << endl; } void func(){ cout << "派生クラスのfunc関数です" << endl; } void func2(){ cout << "派生クラスのfunc2関数です" << endl; } }; int main(){ // オブジェクトを作成するとコンストラクタが実行される。 cout << "check : 1" << endl; Base b1; b1.func(); // 派生クラスのオブジェクトを作成すると、 // 基本クラスと派生クラスのコンストラクタ両方が実行される。 // また、基本クラスfunc関数と同名の関数を派生クラスでも作ると // 「オーバーライド」され、基本クラスの動きとは異なる動きにできる。 cout << "\ncheck : 2" << endl; Derive d2; d2.func(); // 一方オブジェクトを作成しないでポインタだけ作成するとコンストラクタは実行されない。 // しかし、関数は実行できる。 cout << "\ncheck : 3" << endl; Base* bp3; bp3->func(); // 派生クラスのポインタも同様に、コンストラクタは実行されない。 // しかし、関数は実行できる。 // ここで実行されるのは、オーバーライドされた派生クラスの関数。 cout << "\ncheck : 4" << endl; Derive* dp4; dp4->func(); // 派生クラスのオブジェクトは基本クラスのポインタで指すことができる。 // しかし、基本クラスの関数が実行されてしまう。 cout << "\ncheck : 5" << endl; Base* bp5; Derive d5; // 基本クラスと派生クラスのコンストラクタは両方ここで実行される bp5 = &d5; bp5->func(); // 派生クラスのオブジェクトなのだから、派生クラスの方のfunc関数を実行させたい。 // そのためには基本クラスの関数に「virtual」指定をつけて仮想関数にしておく。 // 基本クラスでvirtual指定しておいたfunc2関数を派生クラスにオーバーライドし、 // 派生クラスのfunc2関数を実行する。 // ちゃんと自分が基本クラスのオブジェクトと派生クラスのオブジェクトの // どちらをを指しているのか判断して、適した関数を実行してくれる。 cout << "\ncheck : 6" << endl; Base *bp6_1, *bp6_2; Base b6; bp6_1 = &b6; bp6_1->func2(); Derive d6; // 基本クラスと派生クラスのコンストラクタは両方ここで実行される bp6_2 = &d6; bp6_2->func2(); return 0; }
【実行結果】
$ check : 1 基本クラスのコンストラクタです 基本クラスのfunc関数です check : 2 基本クラスのコンストラクタです 派生クラスのコンストラクタです 派生クラスのfunc関数です check : 3 基本クラスのfunc関数です check : 4 派生クラスのfunc関数です check : 5 基本クラスのコンストラクタです 派生クラスのコンストラクタです 基本クラスのfunc関数です check : 6 基本クラスのコンストラクタです 基本クラスのfunc2関数です 基本クラスのコンストラクタです 派生クラスのコンストラクタです 派生クラスのfunc2関数です $