新規記事の投稿を行うことで、非表示にすることが可能です。
2017年12月21日
《その192》 仮想関数の利用( 単純な例 ;^ω^A )
自分でちょっと確認したいことがあって作ったプログラムです。仮想関数が、クラスオブジェクトの動的な型に応じて動作する単純なプログラムです。
※ 派生クラスの中の基底クラス部分オブジェクトへのアクセス(name, tool へのアクセス)について、自分がチェックしてみたいことがあって作ったプログラムです。
// ------------------------------------
#include <string>
#include <iostream>
using namespace std;
class Man0 {
string name;
string tool;
public:
Man0(string na, string tl = "ハサミ")
: name(na), tool(tl) { }
string get_name() { return name; }
string get_tool() { return tool; }
void set_tool(string s) { tool = s; }
virtual void hello() { cout << "こんにちは。"; }
void my_name() {
cout << "私は" << name << "です。";
}
virtual void func() {
cout << tool << "を持っています。\n";
}
};
class Man1 : public Man0 {
string tool;
public:
Man1(string na, string tl = "定規")
: Man0(na), tool(tl) { }
void set_tool(string s, string s2) {
Man0::set_tool(s); tool = s2;
}
void hello() { cout << "よろしくね。"; }
void func() {
cout << get_tool() << "と"
<< tool << "を持っているよ。\n";
}
};
void statement(Man0& x) {
x.hello();
x.my_name();
x.func();
}
int main() {
Man0 tanaka("田中");
Man1 nakada("中田");
statement(tanaka);
statement(nakada);
cout << '\n';
tanaka.set_tool("画用紙");
nakada.set_tool("クレヨン", "鉛筆");
statement(tanaka);
statement(nakada);
}
// ------------------------------------
![f05_0031.png](/cplusplus/file/f05_0031.png)
《その191》 仮想関数,仮想デストラクタ,多相的クラス
virtual無し と virtual有りの 短いプログラムを比較して、仮想関数,仮想デストラクタ,多相的クラス の再確認をしてみたいと思います。
◆ virtual無し
// ------------------------------------
#include <iostream>
using namespace std;
class Aaa {
public:
Aaa() { cout << "constructor Aaa\n"; }
~Aaa() { cout << "destructor Aaa\n"; }
void f() const { cout << "Aaa\n"; }
};
class Bbb : public Aaa{
public:
int b = 20;
Bbb() { cout << "constructor Bbb\n"; }
~Bbb() { cout << "destructor Bbb\n"; }
void f() const { cout << "Bbb\n"; }
};
void func(Aaa& x) {
x.f();
}
int main() {
cout << "(1)\n";
Aaa* ptr = new Bbb;
cout << "------\n";
cout << "(2)\n";
delete ptr;
cout << "------\n";
cout << "(3)\n";
Bbb b;
cout << "------\n";
cout << "(4)\n";
func(b);
cout << "------\n";
cout << "(5)\n";
}
// ------------------------------------
![f05_0021.png](/cplusplus/file/f05_0021.png)
(1)
動的に領域を確保して、Bbb型オブジェクトを作成するので、
基底クラスのコンストラクタ Aaa が呼び出され、
→ "constructor Aaa"を表示
次いで、派生クラスのコンストラクタ Bbb が呼び出されます。
→ "constructor Bbb"を表示
(2)
Aaa, Bbb は多相的クラスではないのでポインタ ptr は静的な型 Aaa*。よって、デストラクタ ~Aaa が呼ばれます。
→ "destructor Aaa"を表示
(3)
Bbb型オブジェクトを作成するので、
基底クラスのコンストラクタ Aaa が呼び出され、
→ "constructor Aaa"を表示
次いで、派生クラスのコンストラクタ Bbb が呼び出されます。
→ "constructor Bbb"を表示
(4)
関数 func の仮引数は Aaa&型。f() は仮想関数ではないので、Aaa::f() が呼び出されます。
→ "Aaa"を表示
(5)
プログラムの終了時に オブジェクト b を破棄するので、
デストラクタ ~Bbb が呼び出され、
→ "destructor ~Bbb"を表示
次いで、デストラクタ ~Aaa が呼び出されます。
→ "destructor ~Aaa"を表示
◆ virtual有り
// ------------------------------------
#include <iostream>
using namespace std;
class Aaa {
public:
Aaa() { cout << "constructor Aaa\n"; }
virtual ~Aaa() { cout << "destructor Aaa\n"; }
virtual void f() const { cout << "Aaa\n"; }
};
class Bbb : public Aaa{
public:
int b = 20;
Bbb() { cout << "constructor Bbb\n"; }
~Bbb() { cout << "destructor Bbb\n"; }
void f() const { cout << "Bbb\n"; }
};
void func(Aaa& x) {
x.f();
}
int main() {
cout << "(1)\n";
Aaa* ptr = new Bbb;
cout << "------\n";
cout << "(2)\n";
delete ptr;
cout << "------\n";
cout << "(3)\n";
Bbb b;
cout << "------\n";
cout << "(4)\n";
func(b);
cout << "------\n";
cout << "(5)\n";
}
// ------------------------------------
![f05_0022.png](/cplusplus/file/f05_0022.png)
(1)
動的に領域を確保して、Bbb型オブジェクトを作成するので、
基底クラスのコンストラクタ Aaa が呼び出され、
→ "constructor Aaa"を表示
次いで、派生クラスのコンストラクタ Bbb が呼び出されます。
→ "constructor Bbb"を表示
(2)
Aaa, Bbb は多相的クラスであるからポインタ ptr は動的な型 Bbb*。よって、
デストラクタ ~Bbb が呼ばれ、
→ "destructor ~Bbb"を表示
次いで、デストラクタ ~Aaa が呼ばれます。
→ "destructor ~Aaa"を表示
(3)
Bbb型オブジェクトを作成するので、
基底クラスのコンストラクタ Aaa が呼び出され、
→ "constructor Aaa"を表示
次いで、派生クラスのコンストラクタ Bbb が呼び出されます。
→ "constructor Bbb"を表示
(4)
関数 func の仮引数は Aaa&型ですが、f() が仮想関数なので、Bbb::f() が呼び出されます。
→ "Bbb"を表示
(5)
プログラムの終了時に オブジェクト b を破棄するので、
デストラクタ ~Bbb が呼び出され、
→ "destructor ~Bbb"を表示
次いで、デストラクタ ~Aaa が呼び出されます。
→ "destructor ~Aaa"を表示