網站首頁 編程語言 正文
基類實現
我們先實現一個基類
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類中我們實現了一個虛函數display和 func。
BaseTest類內部重載了f1函數,實現了兩個版本,一個參數為string一個參數為int。
同一個類中的多個同名函數叫做重載。
實現了普通函數say,exec以及exec2函數。exec和exec2函數內部調用了display和say函數。
子類實現
子類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 子類重新實現了display和func函數,子類重新實現父類的虛函數,叫做重寫。
同樣子類重新實現了f1和say函數,由于父類有f1和say,所以子類重新實現覆蓋了父類的函數,
這種普通函數被子類重寫導致父類的函數被隱藏了,叫做覆蓋。
函數調用
接下來我們通過函數調用,看一下覆蓋,重載和重寫的區別
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();會根據多態的效果調用子類DeriveA的func函數
2 ? a.func() 因為a是一個對象,所以調用子類DeriveA的func函數
3 ? b->f1(“abc”) 調用基類BaseTest的f1,因為f1是一個普通函數
4 ? a.f1(3, 5) 調用DeriveA的f1,因為a是一個普通對象。
5 ? 當我們想在子類里調用基類的f1函數,可以通過基類作用域加函數名的方式,比如例子中的
a.use_base_f1就在函數內部通過BaseTest::f1調用了基類函數f1
6 ? b->exec,首先b是一個指針且exec為普通函數只在基類實現了,所以調用基類的exec,
但是exec內部調用了虛函數display,此時觸發多態機制調用DeriveA的display函數,因為b是一個指向子類DeriveA對象的基類BaseTest指針,exec內部調用了普通函數display,因為display不是虛函數,所以調用BaseTest的display函數
7 ? a.exec(); a是一個DeriveA對象,DeriveA自己沒有實現exec函數,所以調用基類BaseTest的exec函數,exec內部調用display虛函數時由于DeriveA重寫了display函數,所以調用DeriveA的display函數,exec內部調用say函數時由于say是普通函數,所以此時調用的是BaseTest的say函數。
8 ? c->exec(); 因為c為BaseTest類型,所以調用的就是BaseTest的exec,內部執行的也是BaseTest的display和say。
9 ?b->exec2(); 因為b是一個子類BaseTest的指針,所以調用BaseTest的exec2函數,exec2內部調用display時觸發多態機制調用DeriveA的display,調用say時因為say是普通函數,所以調用BaseTest的say函數。
10 ? a.exec2(); 因為a是DeriveA類對象,且DeriveA實現了exec2,所以a調用DeriveA的exec2,這樣exec2內部調用的都是DeriveA的say和display
11 ? c->exec2(); c為BaseTest類對象,所以調用BaseTest類的exec2以及display和say函數。
總結
考察一個函數是被子類還是基類調用時應該分以下幾種情況
1 ?該函數是虛函數并且被子類重寫,如果是基類指針指向子類對象,調用該函數則引發多態機制,調用子類的虛函數
2 ? 如果該函數時虛函數并且沒有被重寫,那么無論調用的對象是基類指針還是子類對象,還是基類對象,
還是子類指針都是調用基類的這個虛函數
3 ? 如果該函數不是虛函數,如果該函數被子類覆蓋(子類重新定義了同名函數),那么調用規則就是子類調用子類的該函數,
基類調用該基類的函數。
4 ? 如果該函數不是虛函數,并且子類沒有定義同名函數(沒有覆蓋基類同名函數),那么無論是子類還是基類的指針或者對象,
統一調用的是基類的函數。
5 ? 如果第4點里基類的函數(沒有被子類覆蓋),但是內部調用了基類的虛函數,并且該虛函數被子類重寫,這時內部這個虛函數調用規則
就要看調用對象的實際類型,符合1的調用標準,多態就走子類,不是多態就走基類(此時符合2標準)
6 ?如果第3點里基類的函數(被子類覆蓋),但是內部調用了基類的虛函數,并且該虛函數被子類重寫,這時內部這個虛函數調用規則
就要看調用對象的實際類型,符合1的調用標準,多態就走子類,不是多態就走基類(此時符合2標準)
資源鏈接
本文模擬實現了vector的功能。
視頻鏈接
源碼鏈接?
原文鏈接:https://blog.csdn.net/secondtonone1/article/details/126046408
相關推薦
- 2023-01-09 No?module?named?'plotly.graph_objects'報錯解決_python
- 2023-02-17 Python的OptionParser模塊示例教程_python
- 2022-12-03 FFmpeg?Principle學習open_output_file打開輸出文件_Android
- 2022-08-19 vscode遠程免密登入Linux服務器的配置方法_Linux
- 2022-05-01 Python?Pandas讀取Excel日期數據的異常處理方法_python
- 2022-03-23 Asp.Net?Core?使用Monaco?Editor?實現代碼編輯器功能_實用技巧
- 2022-04-06 用Python實現一個簡單的用戶系統_python
- 2022-04-19 Django的開發步驟原來是這樣的_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支