新規記事の投稿を行うことで、非表示にすることが可能です。
2017年12月18日
《その187》 仮想関数,多相的クラス(前々回《185》の参考資料のみ)
前回《186》、参考資料を追加したついでに、m(_ _)m さらにあと一つだけ追加させてください。
前々回《185》のプログラムコードの、
関数 void print(Aaa& x);
関数 int main();
を次のコードに入れ替えると、前々回《185》のプログラムでは仮引数 x が参照でしたが、x がポインタであっても同じだということを確認していただけると思います。
// ------------------------------------
void print(Aaa* x) {
x->statement();
cout << typeid(*x).name() << '\n';
}
int main() {
Aaa obj_a;
Bbb obj_b;
Ccc obj_c;
print(&obj_a);
print(&obj_b);
print(&obj_c);
}
// ------------------------------------
結果は、前々回《185》と同じなので、省略します。
《その186》 仮想関数,多相的クラス(前回《185》の参考資料のみ)
《その185》 仮想関数,多相的クラス
仮想関数
まず、今回のプログラムの概略です。
基底クラス Base と、Base の public派生クラス Der1, Der2 があります。それぞれのクラスのメンバ関数 statement は仮想関数("virtual"が付加されている,関数名が同じ,仮引数が同じ)です。
main関数では、
Base型のオブジェクト bas
Der1型のオブジェクト de1
Der2型のオブジェクト de2
を作成し、各オブジェクトを引数にして、関数 print を呼び出します。関数 print は、それらのオブジェクトへの参照を受け取ります。
関数 print(Base& x); は、Base&型の仮引数で各オブジェクトへの参照を受け取ります。
そして、受け取った参照先オブジェクトの動的な型に応じた仮想関数 statement が呼び出されることになります。
bas の動的な型は Base型なので、呼び出されるのは Base::statement()
de1 の動的な型は Der1型なので、呼び出されるのは Der1::statement()
de2 の動的な型は Der2型なので、呼び出されるのは Der2::statement()
となります。
また、関数 print(Base& x); は、
各オブジェクトの型を、typeid演算子を用いて出力します。
typeid演算子が返す型については、下記の多相的クラスの項目をご覧ください。
多相的クラス
仮想関数を含むクラスは、多相的クラスと呼ばれる特殊なクラスです。
クラス Base は、仮想関数 statement を持っている
クラス Der1 は、仮想関数 statement を持っている
クラス Der2 は、仮想関数 statement を持っている
ので、すべて多相的クラスということになります。
多相的クラスであるため、関数 print(Base& x); の仮引数 x の参照先の型は、動的な型であると解釈されます。
typeid演算子は、その動的な型を返却します。
下記のプログラムの出力結果は、次のようになります。
また、もし、各クラスの virtual print(Base& x); から virtual を取り除いて、仮想関数ではない状態にした場合の、出力結果は、次のようになります。
// ------------------------------------
#include <typeinfo>
#include <iostream>
using namespace std;
class Base {
int a;
public:
Base(int x = 10) : a(x) { }
int get_a() const { return a; }
// 仮想関数
virtual void statement() const {
cout << "基底クラス Base\n";
}
};
class Der1 : public Base {
int b;
public:
Der1(int x = 20, int y = 22)
: Base(x), b(y) { }
int get_b() const { return b; }
// 派生クラスの "virtual" は省略可能です。
virtual void statement() const {
cout << "派生クラス Der1\n";
}
};
class Der2 : public Base {
int c;
public:
Der2(int x = 30, int y = 33)
: Base(x), c(y) { }
int get_c() const { return c; }
// 派生クラスの "virtual" は省略可能です。
virtual void statement() const {
cout << "派生クラス Der2\n";
}
};
void print(Base& x) {
x.statement();
cout << typeid(x).name() << '\n';
}
int main() {
Base bas;
Der1 de1;
Der2 de2;
print(bas); cout << '\n';
print(de1); cout << '\n';
print(de2);
}
// ------------------------------------