C++深入探究重載重寫覆蓋的區(qū)別
基類實現(xiàn)
我們先實現(xiàn)一個基類
class BaseTest { private: virtual void display() { cout << "Base display" << endl; } void say() { cout << "Base say()" << endl; } public: virtual void func() { cout << "Base func()" << endl; } void exec() { display(); say(); } void f1(string a) { cout << "Base f1(string)" << endl; } void f1(int a) { cout << "Base f1(int)" << endl; } void exec2() { display(); say(); } };
BaseTest類中我們實現(xiàn)了一個虛函數(shù)display和 func。
BaseTest類內(nèi)部重載了f1函數(shù),實現(xiàn)了兩個版本,一個參數(shù)為string一個參數(shù)為int。
同一個類中的多個同名函數(shù)叫做重載。
實現(xiàn)了普通函數(shù)say,exec以及exec2函數(shù)。exec和exec2函數(shù)內(nèi)部調(diào)用了display和say函數(shù)。
子類實現(xiàn)
子類DeriveA繼承了基類
class DeriveA : public BaseTest { public: void display() { cout << "DeriveA display()" << endl; } void f1(int a, int b) { cout << "DeriveA f1(int,int)" << endl; } void say() { cout << "DeriveA say()" << endl; } virtual void func() { cout << "DeriveA func()" << endl; } void use_base_f1(int a, int b) { BaseTest::f1(2); BaseTest::f1("test"); cout << "DeriveA f1(int, int)" << endl; } void exec2() { display(); say(); } };
子類DeriveA 子類重新實現(xiàn)了display和func函數(shù),子類重新實現(xiàn)父類的虛函數(shù),叫做重寫。
同樣子類重新實現(xiàn)了f1和say函數(shù),由于父類有f1和say,所以子類重新實現(xiàn)覆蓋了父類的函數(shù),
這種普通函數(shù)被子類重寫導(dǎo)致父類的函數(shù)被隱藏了,叫做覆蓋。
函數(shù)調(diào)用
接下來我們通過函數(shù)調(diào)用,看一下覆蓋,重載和重寫的區(qū)別
void derive_base_test1() { DeriveA a; BaseTest *b = &a; shared_ptr<BaseTest> c = make_shared<BaseTest>(); //輸出DeriveA func() b->func(); //輸出DeriveA func() a.func(); //輸出Base f1(string) b->f1("abc"); //輸出Base f1(int) b->f1(3); //輸出DeriveA f1(int,int) a.f1(3, 5); a.use_base_f1(2, 4); cout << "========================" << endl; //輸出DeriveA display() //輸出Base say() b->exec(); //輸出DeriveA display() //輸出Base say() a.exec(); //輸出Base display //輸出Base say() c->exec(); cout << "======================== \n" << endl; //輸出 DeriveA display() //輸出 Base say() b->exec2(); //輸出 DeriveA display() //輸出 DeriveA say() a.exec2(); //輸出 Base display //輸出 Base say() c->exec2(); }
代碼里我們生成了一個DeriveA的實例a, 并將該實例返回給基類BaseTest的指針b,所以:
1 b->func();會根據(jù)多態(tài)的效果調(diào)用子類DeriveA的func函數(shù)
2 a.func() 因為a是一個對象,所以調(diào)用子類DeriveA的func函數(shù)
3 b->f1(“abc”) 調(diào)用基類BaseTest的f1,因為f1是一個普通函數(shù)
4 a.f1(3, 5) 調(diào)用DeriveA的f1,因為a是一個普通對象。
5 當我們想在子類里調(diào)用基類的f1函數(shù),可以通過基類作用域加函數(shù)名的方式,比如例子中的
a.use_base_f1就在函數(shù)內(nèi)部通過BaseTest::f1調(diào)用了基類函數(shù)f1
6 b->exec,首先b是一個指針且exec為普通函數(shù)只在基類實現(xiàn)了,所以調(diào)用基類的exec,
但是exec內(nèi)部調(diào)用了虛函數(shù)display,此時觸發(fā)多態(tài)機制調(diào)用DeriveA的display函數(shù),因為b是一個指向子類DeriveA對象的基類BaseTest指針,exec內(nèi)部調(diào)用了普通函數(shù)display,因為display不是虛函數(shù),所以調(diào)用BaseTest的display函數(shù)
7 a.exec(); a是一個DeriveA對象,DeriveA自己沒有實現(xiàn)exec函數(shù),所以調(diào)用基類BaseTest的exec函數(shù),exec內(nèi)部調(diào)用display虛函數(shù)時由于DeriveA重寫了display函數(shù),所以調(diào)用DeriveA的display函數(shù),exec內(nèi)部調(diào)用say函數(shù)時由于say是普通函數(shù),所以此時調(diào)用的是BaseTest的say函數(shù)。
8 c->exec(); 因為c為BaseTest類型,所以調(diào)用的就是BaseTest的exec,內(nèi)部執(zhí)行的也是BaseTest的display和say。
9 b->exec2(); 因為b是一個子類BaseTest的指針,所以調(diào)用BaseTest的exec2函數(shù),exec2內(nèi)部調(diào)用display時觸發(fā)多態(tài)機制調(diào)用DeriveA的display,調(diào)用say時因為say是普通函數(shù),所以調(diào)用BaseTest的say函數(shù)。
10 a.exec2(); 因為a是DeriveA類對象,且DeriveA實現(xiàn)了exec2,所以a調(diào)用DeriveA的exec2,這樣exec2內(nèi)部調(diào)用的都是DeriveA的say和display
11 c->exec2(); c為BaseTest類對象,所以調(diào)用BaseTest類的exec2以及display和say函數(shù)。
總結(jié)
考察一個函數(shù)是被子類還是基類調(diào)用時應(yīng)該分以下幾種情況
1 該函數(shù)是虛函數(shù)并且被子類重寫,如果是基類指針指向子類對象,調(diào)用該函數(shù)則引發(fā)多態(tài)機制,調(diào)用子類的虛函數(shù)
2 如果該函數(shù)時虛函數(shù)并且沒有被重寫,那么無論調(diào)用的對象是基類指針還是子類對象,還是基類對象,
還是子類指針都是調(diào)用基類的這個虛函數(shù)
3 如果該函數(shù)不是虛函數(shù),如果該函數(shù)被子類覆蓋(子類重新定義了同名函數(shù)),那么調(diào)用規(guī)則就是子類調(diào)用子類的該函數(shù),
基類調(diào)用該基類的函數(shù)。
4 如果該函數(shù)不是虛函數(shù),并且子類沒有定義同名函數(shù)(沒有覆蓋基類同名函數(shù)),那么無論是子類還是基類的指針或者對象,
統(tǒng)一調(diào)用的是基類的函數(shù)。
5 如果第4點里基類的函數(shù)(沒有被子類覆蓋),但是內(nèi)部調(diào)用了基類的虛函數(shù),并且該虛函數(shù)被子類重寫,這時內(nèi)部這個虛函數(shù)調(diào)用規(guī)則
就要看調(diào)用對象的實際類型,符合1的調(diào)用標準,多態(tài)就走子類,不是多態(tài)就走基類(此時符合2標準)
6 如果第3點里基類的函數(shù)(被子類覆蓋),但是內(nèi)部調(diào)用了基類的虛函數(shù),并且該虛函數(shù)被子類重寫,這時內(nèi)部這個虛函數(shù)調(diào)用規(guī)則
就要看調(diào)用對象的實際類型,符合1的調(diào)用標準,多態(tài)就走子類,不是多態(tài)就走基類(此時符合2標準)
資源鏈接
本文模擬實現(xiàn)了vector的功能。
到此這篇關(guān)于C++深入探究重載重寫覆蓋的區(qū)別的文章就介紹到這了,更多相關(guān)C++重載重寫覆蓋內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++?中如何結(jié)束?while?(cin>>str)?的輸入
這篇文章主要介紹了C++?中如何結(jié)束?while?(cin>>str)?的輸入,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07