关于虚函数的应用(10个例子)
虛函數(shù)是C++中非常重要的一個(gè)概念,它最大的好處是能夠觸發(fā)動(dòng)態(tài)綁定。C++中的函數(shù)默認(rèn)不使用動(dòng)態(tài)綁定,要觸發(fā)動(dòng)態(tài)綁定,必須滿足 兩個(gè)條件:
第一,只有指定為虛函數(shù)的成員函數(shù)才能進(jìn)行動(dòng)態(tài)綁定,成員函數(shù)默認(rèn)為非虛函數(shù),非虛函數(shù)不進(jìn)行動(dòng)態(tài)綁定;
第二,必須通過基類類型的指針或引用進(jìn)行函數(shù)的調(diào)用。具體理解指針或引用在使用繼承層次中某一類型的對(duì)象時(shí)會(huì)發(fā)生什么,本文不展開討論,
這兩天主要研習(xí)了虛函數(shù)的具體應(yīng)用這一塊,而它的應(yīng)用又非常廣泛,學(xué)MFC的應(yīng)該能夠感受到它的強(qiáng)大,要說是總結(jié)也不一定能夠總結(jié)全,本人目前也處在studying中,所以用10個(gè)具體的例子來說明。例子是從難 到易,看到的朋友如果懂前面的可以不用看后面的。每一個(gè)例子就是一個(gè)類,通過類在內(nèi)存中的布局來形象地分析虛函數(shù)究竟是如何運(yùn)作的。圖表示可能抽象一點(diǎn),一般帶有V開頭的表示一個(gè)虛函數(shù)表,如果是學(xué)過編譯原理這門課就很容易看懂,沒學(xué)過的只要懂虛函數(shù)的一些機(jī)制,耐著性子也是沒問題的。每個(gè)圖示都配有相應(yīng)的代碼。可以對(duì)照著代碼來看。
1、??虛函數(shù)繼承的復(fù)雜例子
2、??菱形繼承無虛擬繼承的情況
3、??虛擬繼承的簡單情況
4、??單一普通繼承(無虛函數(shù))
5、??單一繼承(含虛函數(shù))(虛函數(shù)表只有一個(gè))
6、??多重繼承(不含虛函數(shù))
7、??多重繼承(一個(gè)含虛函數(shù),一個(gè)不含虛函數(shù))
8、??多重繼承(兩個(gè)都含有虛函數(shù))
9、??純虛汗繼承
10、?private?的虛函數(shù)
?
1、虛函數(shù)繼承的復(fù)雜例子,見下圖:
見圖:左邊是這個(gè)類的內(nèi)存布局,右邊是繼承圖示。 farther類和Uncle類都是虛擬繼承,其內(nèi)部也都有偏移表,但我覺得這兩個(gè)表只是內(nèi)部隱藏的,不在Son的內(nèi)存布局中表示出來,本題Son的內(nèi)存只有32個(gè)字節(jié),如果表示出來就不止32個(gè)了,但是下面這個(gè)地方在內(nèi)存中顯示是00 00 00 00,我猜想是不是GrandFather的偏移地址。
| VbtSon(Father) |
| Farther~Num |
| VbtSon(Uncle) |
| Uncle~Num |
| Son~Num |
| Offset(這個(gè)地方??) |
| Vftable(GrandFather) |
| GrandFather~Num |
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?
?例子代碼:
1 class GrandFather2 {3 public:4 GrandFather():i_G(5){cout<<"GrandFather() is called!"<<endl;}5 virtual ~GrandFather(){cout<<"~GrandFather() is called!"<<endl;}6 public:7 virtual void Test(){cout<<"GrandFather::Test() is called!"<<endl;}8 private:9 int i_G; 10 }; 11 12 class Father: virtual public GrandFather //虛擬繼承 13 { 14 public: 15 Father():i_F(7){cout<<"Father() is called!"<<endl;}; 16 virtual ~Father(){cout<<"~Father() is called!"<<endl;} 17 public: 18 virtual void Test(){cout<<"Father::Test() is called!"<<endl;} 19 private: 20 int i_F; 21 }; 22 23 class Uncle: virtual public GrandFather //虛擬繼承 24 { 25 public: 26 Uncle():i_U(3){cout<<"Uncle is called!"<<endl;} 27 virtual ~Uncle(){cout<<"~Uncle is called!"<<endl;} 28 public: 29 virtual void Test(){cout<<"Uncle ::Test() is called!"<<endl;} 30 private: 31 int i_U; 32 }; 33 34 class Son:public Father,public Uncle 35 { 36 public: 37 Son():i_S(9){cout<<"Son is called!"<<endl;}; 38 virtual ~Son(){cout<<"~Son is called!"<<endl;} 39 public: 40 virtual void Test(){cout<<"Son ::Test() is called!"<<endl;} 41 private: 42 int i_S; 43 }; 44 45 int main(void) 46 { 47 Son p; 48 p.Test(); 49 cout<<sizeof(Son)<<endl; 50 cout<<sizeof(Father)<<endl; 51 cout<<sizeof(GrandFather)<<endl; 52 return 0; 53 }運(yùn)行情況:
?
2、??菱形繼承無虛擬繼承的情況
| VPTr1(Father) |
| GrandFarther~Num |
| Father~Num |
| VPtr(Uncle) |
| GrandFarther~Num |
| Uncle~Num |
| Son~Num |
? ? ? ? ? ? ? ? ? ? ? ? ?
1 #include<iostream>2 using namespace std;3 class GrandFather4 {5 public:6 GrandFather():i_G(5){cout<<"GrandFather() is called!"<<endl;}7 virtual ~GrandFather(){cout<<"~GrandFather() is called!"<<endl;}8 public:9 virtual void Test(){cout<<"GrandFather::Test() is called!"<<endl;} 10 private: 11 int i_G; 12 }; 13 class Father: public GrandFather //無虛擬繼承 14 { 15 public: 16 Father():i_F(7){cout<<"Father() is called!"<<endl;}; 17 virtual ~Father(){cout<<"~Father() is called!"<<endl;} 18 public: 19 virtual void Test(){cout<<"Father::Test() is called!"<<endl;} 20 private: 21 int i_F; 22 }; 23 24 class Uncle: public GrandFather //無虛擬繼承 25 { 26 public: 27 Uncle():i_U(3){cout<<"Uncle is called!"<<endl;} 28 virtual ~Uncle(){cout<<"~Uncle is called!"<<endl;} 29 public: 30 virtual void Test(){cout<<"Uncle ::Test() is called!"<<endl;} 31 private: 32 int i_U; 33 }; 34 35 class Son:public Father,public Uncle 36 { 37 public: 38 Son():i_S(9){cout<<"Son is called!"<<endl;}; 39 virtual ~Son(){cout<<"~Son is called!"<<endl;} 40 public: 41 virtual void Test(){cout<<"Son ::Test() is called!"<<endl;} 42 private: 43 int i_S; 44 }; 45 46 int main(void) 47 { 48 Son p; 49 p.Test(); 50 cout<<sizeof(Son)<<endl; 51 cout<<sizeof(Father)<<endl; 52 cout<<sizeof(GrandFather)<<endl; 53 54 return 0; 55 }運(yùn)行情況:
? ? ? ? ? ??
3、??虛擬繼承的簡單情況 見下圖:
| VPTrD(A) ? ? ? ? ? ? ?4 ? ? ? |
| Offset(A) ? ? ? ? ? ? ?4 |
| A~number ? ? ? ? ? ? 4 |
| D~number ? ? ? ? ? ? 4 |
| VPtr(Base) ? ? ? ? ? ?4 |
| Base~Number ? ? 12 + 3cc + 4 = 40 |
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
1 class Base2 {3 public:4 Base(){strcpy_s(ch_rc,"abcdefg");} //初始化Base()::im5 public:6 virtual void Read(){cout<<"Base::Read()is called!"<<endl;}7 private:8 char ch_rc[12];9 bool ir; 10 int im; 11 }; 12 class A: virtual public Base //虛擬繼承 13 { 14 public: 15 A():im_A(5){} //初始化A()::im_A 16 public: 17 virtual void Read(){cout<<"A::Read()is called!"<<endl;} 18 private: 19 int im_A; 20 }; 21 class D:public A 22 { 23 public: 24 D():im_D(3){} 25 public: 26 virtual void Read(){cout<<"D::Read()is called!"<<endl;} 27 private: 28 int im_D; 29 }; 30 int _tmain(int argc, _TCHAR* argv[]) 31 { 32 D obj; 33 cout<<sizeof(D)<<endl; 34 return 0; 35 }運(yùn)行情況:
?
4、單一普通繼承(無虛函數(shù))(這個(gè)沒什么好說的)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 內(nèi)存布局
| Father~Number |
| Son~Number |
?
5、單一繼承(含虛函數(shù))(虛函數(shù)表只有一個(gè))見圖:
| VPTr(father) |
| Father~number |
| Son~number |
| Child~number |
? ? ? ? ? ? ? ? ? ? ? ??
1 #include<iostream>2 using namespace std;3 class Father4 {5 public:6 Father(){cout<<"Father() is called!"<<endl;}7 virtual void Test(){cout<<"Base::Test() is called!"<<endl;}8 virtual ~Father(){cout<<"~Father() is called!"<<endl;}9 private: 10 int i_B; 11 }; 12 13 class Son:public Father 14 { 15 public: 16 Son():i_A(5){cout<<"Son() is called!"<<endl;} 17 void Test(){cout<<"Son::Test() is called!"<<endl;} 18 ~Son(){cout<<"~Son() is called!"<<endl;} 19 private: 20 int i_A; 21 }; 22 int main(int argc,char *argv[]) 23 { 24 Father *p=new Son; 25 //Father *p=NULL; 26 p->Test(); 27 delete p; 28 p=NULL; 29 cout<<sizeof(Son)<<endl; 30 return 0; 31 }運(yùn)行情況:
?
6、多重繼承(不含虛函數(shù))(這個(gè)也沒什么好說的)
直接看代碼:
1 #include<iostream>2 using namespace std;3 class Father4 {5 public:6 Father():i_B(6){cout<<"Father() is called!"<<endl;}7 void TestF(const int &m){8 i_B=m;9 cout<<"Father::TestF() is called!"<<endl; 10 } 11 void Test(){cout<<"Father::Test() is called!"<<endl;} 12 ~Father(){cout<<"~Father() is called!"<<endl;} 13 private: 14 int i_B; 15 }; 16 class Son 17 { 18 public: 19 Son():i_A(5){cout<<"Son() is called!"<<endl;} 20 void Test(){cout<<"Son::Test() is called!"<<endl;} 21 ~Son(){cout<<"~Son() is called!"<<endl;} 22 private: 23 int i_A; 24 }; 25 26 class Child:public Father,public Son //多重繼承 27 { 28 public: 29 Child():i_C(5){cout<<"Child() is called!"<<endl;} 30 void Test(){cout<<"Child::Test() is called!"<<endl;} 31 ~Child(){cout<<"~Child() is called!"<<endl;} 32 private: 33 int i_C; 34 }; 35 int main(int argc,char *argv[]) 36 { 37 Father *p=new Child; 38 //Father *p=NULL; 39 p->Test(); 40 cout<<sizeof(Son)<<endl; 41 cout<<sizeof(Child)<<endl; 42 return 0; 43 }?
7、多重繼承(一個(gè)含虛函數(shù),一個(gè)不含虛函數(shù))(類似單一繼承)
| VPTr(father) |
| Father~number |
| Son~number |
| Child~number |
? ? ? ? ? ? ? ? ? ? ? ? ?
1 #include<iostream>2 using namespace std;3 4 class Father5 {6 public:7 Father():i_B(6){cout<<"Father() is called!"<<endl;}8 virtual void TestF(const int &m){9 i_B=m; 10 cout<<"Father::TestF() is called!"<<endl; 11 } 12 virtual void Test(){cout<<"Father::Test() is called!"<<endl;} 13 virtual ~Father(){cout<<"~Father() is called!"<<endl;} 14 private: 15 int i_B; 16 }; 17 18 class Son 19 { 20 public: 21 Son():i_A(5){cout<<"Son() is called!"<<endl;} 22 void Test(){cout<<"Son::Test() is called!"<<endl;} 23 ~Son(){cout<<"~Son() is called!"<<endl;} 24 private: 25 int i_A; 26 }; 27 28 class Child:public Father,public Son 29 { 30 public: 31 Child():i_C(5){cout<<"Child() is called!"<<endl;} 32 void Test(){cout<<"Child::Test() is called!"<<endl;} 33 ~Child(){cout<<"~Child() is called!"<<endl;} 34 private: 35 int i_C; 36 }; 37 int main(int argc,char *argv[]) 38 { 39 Father *p=new Child; 40 //Father *p=NULL; 41 p->Test(); 42 cout<<sizeof(Son)<<endl; 43 cout<<sizeof(Child)<<endl; 44 return 0; 45 }運(yùn)行情況:
?
8、多重繼承(兩個(gè)都含有虛函數(shù))
| VPTr(father) |
| Father~number |
| VPTr(Son) |
| Son~number Child~number ? 20個(gè)字節(jié) |
? ? ? ? ? ? ? ? ? ? ? ? ?
1 #include<iostream>2 using namespace std;3 4 class Father5 {6 public:7 Father():i_B(6){cout<<"Father() is called!"<<endl;}8 virtual void TestF(const int &m){9 i_B=m; 10 cout<<"Father::TestF() is called!"<<endl; 11 } 12 virtual void Test(){cout<<"Father::Test() is called!"<<endl;} 13 virtual ~Father(){cout<<"~Father() is called!"<<endl;} 14 private: 15 int i_B; 16 }; 17 class Son 18 { 19 public: 20 Son():i_A(5){cout<<"Son() is called!"<<endl;} 21 virtual void Test(){cout<<"Son::Test() is called!"<<endl;} 22 virtual ~Son(){cout<<"~Son() is called!"<<endl;} 23 private: 24 int i_A; 25 }; 26 27 class Child:public Father,public Son 28 { 29 public: 30 Child():i_C(7){cout<<"Child() is called!"<<endl;} 31 void Test(){cout<<"Child::Test() is called!"<<endl;} 32 ~Child(){cout<<"~Child() is called!"<<endl;} 33 private: 34 int i_C; 35 }; 36 int main(int argc,char *argv[]) 37 { 38 //Father *p=new Child; 39 Child p; 40 //Father *p=NULL; 41 p.Test(); 42 cout<<sizeof(Son)<<endl; 43 cout<<sizeof(Child)<<endl; 44 return 0; 45 }運(yùn)行情況:
?
9、純虛汗繼承
(只在父類中申明,并在子類中實(shí)現(xiàn)申明的函數(shù)才可以用)
內(nèi)存分配與前面只含虛函數(shù)的情況類似
1 #include<iostream>2 using namespace std;3 class A4 {5 public:6 A():i_A(5){cout<<"A() is called!"<<endl;}7 public:8 virtual void Test()= 0; //prue virtual function9 virtual void Base() {cout<<"this is farther class"<<endl;} 10 private: 11 int i_A; 12 }; 13 14 class B:public A 15 { 16 public: 17 B():i_B(9){} 18 public: 19 void Test() { cout<<" this is SubVirtual!"<<endl;} //必須在子類中實(shí)現(xiàn)該函數(shù)才可以用 20 void Base() { 21 cout<<"this is subclass Base"<<endl; 22 } 23 private: 24 int i_B; 25 }; 26 27 int main(void) 28 { 29 A* p = new B; //multstate pointer 30 p->Test(); 31 p->Base(); 32 cout<<sizeof(B)<<endl; 33 return 0 ; 34 }?
10、private 的虛函數(shù)
1 #include<iostream>2 using namespace std;3 4 class A5 {6 public:7 virtual void Test() { func();}8 private:9 int i_A; 10 virtual void func() {cout<<"A::func () is Called!"<<endl; } 11 }; 12 class B: public A 13 { 14 private: 15 //雖然func()在A類中是private的,但是仍然可以出現(xiàn)在派生類中,并仍然可以與public或者protected的虛函數(shù)一樣產(chǎn)生多態(tài)的效果。 16 virtual void func() { cout<<"B::func() is Called!"<<endl;} private: 17 int i_B; 18 }; 19 20 int main(void) 21 { 22 //A *p=new B; 23 A p; 24 //B p; 25 //p->func(); 26 p.Test(); 27 cout<<sizeof(B)<<endl; 28 return 0; 29 }運(yùn)行情況:
?
?
OK,做這個(gè)東西很辛苦,沒辦法,搞技術(shù)的就得這樣。
寫這些程序然后進(jìn)行測試是很輕松的一件事,然而要把這些東西以文字的方式整理出來,的確不是一件容易的事。所以,就有很多IT高手,技術(shù)流,Coding很厲害,但對(duì)于文字的東西就不是很感冒,不過沒關(guān)系,每個(gè)人有每個(gè)人的不同的需求,我是喜歡沒事總喜歡寫寫的人,我想寫的越多思路就不會(huì)堵塞
祝愿每一個(gè)朋友學(xué)習(xí)愉快,技術(shù)成精!
轉(zhuǎn)載于:https://www.cnblogs.com/zhangyuhang3/p/6868436.html
總結(jié)
以上是生活随笔為你收集整理的关于虚函数的应用(10个例子)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java中正则Matcher类的matc
- 下一篇: ASP.NET Core 菜鸟之路:从S