C++におけるマルチステートにおけるコンストラクション関数とコンストラクション関数の呼び出し

16646 ワード

実験をして,メンバー変数の構造解析,親クラスの構造解析,および虚関数が呼び出しに及ぼす影響を見た.
 1 #include <iostream>
 2 using namespace std;
 3 
 4 class Member
 5 {
 6 public:
 7     Member(int n):m_n1(n)
 8     {
 9         cout<<"Member::Member("<<m_n1<<")"<<endl;
10     }
11     ~Member()
12     {
13         cout<<"Member::~Member("<<m_n1<<")"<<endl;
14     }
15 private:
16     const int m_n1;
17 };
18 
19 class Base
20 {
21 public:
22     Base():m_m1(1)
23     {
24         cout<<"Base::Base()"<<endl;
25         OnConstruct();
26     }
27     ~Base() //         
28     {
29         cout<<"Base::~Base()"<<endl;
30         OnDistruct();
31     }
32     virtual void OnConstruct()
33     {
34         cout<<"Base::OnConstruct()"<<endl;
35     }
36     virtual void OnDistruct()
37     {
38         cout<<"Base::OnDistruct()"<<endl;
39     }
40     virtual void Foo1()
41     {
42         cout<<"Base::Foo1()"<<endl;
43     }
44     void Foo2()
45     {
46         cout<<"Base::Foo2()"<<endl;
47     }
48 
49 private:
50     Member m_m1;//      
51 };
52 
53 class Drived:public Base
54 {
55 public:
56     Drived():m_m2(2)
57     {
58         cout<<"Drived::Drived()"<<endl;
59         OnConstruct();
60     }
61     ~Drived()
62     {
63         cout<<"Drived::~Drived()"<<endl;
64         OnDistruct();
65     }
66     virtual void OnConstruct()
67     {
68         cout<<"Drived::OnConstruct()"<<endl;
69     }
70     virtual void OnDistruct()
71     {
72         cout<<"Drived::OnDistruct()"<<endl;
73     }
74     virtual void Foo1()
75     {
76         cout<<"Drived::Foo1()"<<endl;
77     }
78     void Foo2()//       
79     {
80         cout<<"Drived::Foo2()"<<endl;
81     }
82 private:
83     Member m_m2;//      
84 };
85 
86 int main(int argc, char *argv[])
87 {
88     Base* p = new Drived;
89     p->Foo1();
90     p->Foo2();
91     delete p;
92     return 0;
93 }

このコードの実行出力は次のとおりです.
 1 Member::Member(1)  //             2 Base::Base()       //      3 Base::OnConstruct()//              。        4 Member::Member(2)    //            5 Drived::Drived()     //      6 Drived::OnConstruct()//              。        7 Drived::Foo1()//    ,           8 Base::Foo2()  //   ,           9 Base::~Base()     //       10 Base::OnDistruct()//               11 Member::~Member(1)//        

学生たちは、サブクラスの分析が実行されていないことを見ることができます.どうやって実行に値しますか?親のプロファイルをvirtualに修飾すればよい.
27     ~Base() //         

このように一度実行すると、結果が表示されます(コメントが新しい出力です):
 1 Member::Member(1)
 2 Base::Base()
 3 Base::OnConstruct()
 4 Member::Member(2)
 5 Drived::Drived()
 6 Drived::OnConstruct()
 7 Drived::Foo1()
 8 Base::Foo2()
 9 Drived::~Drived()   //    ,        10 Drived::OnDistruct()//              11 Member::~Member(2)  //         12 Base::~Base()
13 Base::OnDistruct()
14 Member::~Member(1)

まとめてみます.
親ポインタが子オブジェクトを指すことでマルチステートを実現します.
マルチステートの場合、親クラスプロファイルは虚関数に修飾され、サブクラスプロファイルが呼び出されることを保証します.
コンストラクション順序は、親クラスと子クラス(これが最も主要なプロセスであり、後の2つがこの前提である)、初期化リストがコンストラクション前に実行されます.コンストラクション関数では、このクラスの関数(虚関数であるかどうかにかかわらず)が値で呼び出されます.
プロファイル順序は、先子クラスの後親クラス(虚プロファイルに注意)、プロファイルでは本クラスの関数のみが呼び出され、本クラスの後再プロファイル初期化リストのメンバーが呼び出されます.