C++?多態(tài)性實戰(zhàn)之何時使用?virtual?和?override的問題解析
C++ 多態(tài)性實戰(zhàn):何時使用 virtual 和 override?
引言
在面向?qū)ο缶幊讨?,多態(tài)是一個核心概念。很多開發(fā)者在遇到 override 編譯錯誤時,不清楚是否需要將基類函數(shù)聲明為 virtual。本文通過一個實際案例,說明如何判斷是否需要使用多態(tài)。
問題場景
在開發(fā)菜單系統(tǒng)時遇到編譯錯誤:
// 錯誤[Pe1455]:使用"override"聲明的成員函數(shù)并未重寫基類成員
class MenuTripWindow : public MenuSubWindow
{
void ShowImmediate() override; // ? 編譯錯誤
void HideImmediate() override; // ? 編譯錯誤
};基類 MenuSubWindow 中的對應(yīng)函數(shù):
class MenuSubWindow : public BaseWindow
{
void ShowImmediate(); // 非虛函數(shù)
void HideImmediate(); // 非虛函數(shù)
};錯誤原因是:派生類使用 override 但基類函數(shù)不是 virtual,導(dǎo)致無法重寫。
判斷是否需要多態(tài)的三個關(guān)鍵問題
問題1:是否通過基類指針/引用調(diào)用?
查看調(diào)用代碼:
// MenuWindow.cpp
void MenuWindow::SwitchToSubWindow(MenuSubWindow* newWin, sint32 direction)
{
if (m_pCurrentSubWin)
m_pCurrentSubWin->HideImmediate(); // ?? 通過基類指針調(diào)用
// ...
}
void MenuWindow::setVisible(boolean bVisible)
{
MenuSubWindow* target = m_pCurrentSubWin;
if (target != nullptr)
target->ShowImmediate(); // ?? 通過基類指針調(diào)用
}結(jié)論:如果是,則需要多態(tài)。
問題2:派生類是否需要擴(kuò)展基類行為?
查看派生類的實現(xiàn):
// MenuTripWindow.cpp
void MenuTripWindow::ShowImmediate()
{
MenuSubWindow::ShowImmediate(); // 先調(diào)用基類實現(xiàn)
s_bIsVisible = TRUE; // ?? 關(guān)鍵:執(zhí)行額外的邏輯
}
void MenuTripWindow::HideImmediate()
{
MenuSubWindow::HideImmediate(); // 先調(diào)用基類實現(xiàn)
s_bIsVisible = FALSE; // ?? 關(guān)鍵:更新狀態(tài)變量
}派生類不僅要調(diào)用基類實現(xiàn),還要維護(hù)自身的狀態(tài)。如果函數(shù)不是虛函數(shù),通過基類指針調(diào)用時只會執(zhí)行基類版本,派生類的額外邏輯不會執(zhí)行。
結(jié)論:如果需要擴(kuò)展,則必須多態(tài)。
問題3:是否需要統(tǒng)一的接口,但不同子類有不同的實現(xiàn)?
在這個菜單系統(tǒng)中:
MenuTripWindow需要更新s_bIsVisible- 其他子窗口(
MenuPowerWindow、MenuAlcoholWindow等)可能也需要各自的狀態(tài)管理
如果基類函數(shù)不是虛函數(shù),通過統(tǒng)一的 MenuSubWindow* 指針操作時,每個派生類的特殊行為都不會執(zhí)行,導(dǎo)致狀態(tài)不一致。
結(jié)論:如果需要接口統(tǒng)一但實現(xiàn)不同,則需要多態(tài)。
解決方案
方案對比
| 方案 | 優(yōu)點 | 缺點 | 適用場景 |
|---|---|---|---|
| 方案1:移除 override | 簡單快速 | 無法通過基類指針調(diào)用派生類實現(xiàn) | 只通過派生類對象直接調(diào)用 |
| 方案2:添加 virtual(推薦) | 支持多態(tài),行為正確 | 略微增加開銷 | 通過基類指針/引用調(diào)用 |
實施步驟
步驟1:在基類中聲明為 virtual
// MenuSubWindow.h
class MenuSubWindow : public BaseWindow
{
public:
/**
* @brief 立即顯示子窗口(無動畫)
*/
virtual void ShowImmediate(); // ? 添加 virtual
/**
* @brief 立即隱藏子窗口(無動畫)
*/
virtual void HideImmediate(); // ? 添加 virtual
};步驟2:派生類使用 override
// MenuTripWindow.h
class MenuTripWindow : public MenuSubWindow
{
public:
void ShowImmediate() override; // ? 現(xiàn)在可以正常工作
void HideImmediate() override; // ? 現(xiàn)在可以正常工作
};實際效果對比
不使用 virtual(錯誤的行為)
MenuSubWindow* window = new MenuTripWindow(...); window->ShowImmediate(); // 實際調(diào)用:MenuSubWindow::ShowImmediate() // ? MenuTripWindow::ShowImmediate() 中的 s_bIsVisible = TRUE 不會執(zhí)行 // ? 狀態(tài)未更新,可能導(dǎo)致邏輯錯誤
使用 virtual(正確的行為)
MenuSubWindow* window = new MenuTripWindow(...); window->ShowImmediate(); // 實際調(diào)用:MenuTripWindow::ShowImmediate() // ? 先調(diào)用基類實現(xiàn) // ? 然后執(zhí)行 s_bIsVisible = TRUE // ? 狀態(tài)正確更新
決策流程圖
是否需要多態(tài)?
│
├─ 是否通過基類指針/引用調(diào)用?
│ ├─ 是 → 需要 virtual
│ └─ 否 → 繼續(xù)判斷
│
├─ 派生類是否需要擴(kuò)展基類行為?
│ ├─ 是 → 需要 virtual
│ └─ 否 → 繼續(xù)判斷
│
└─ 是否需要統(tǒng)一接口但不同實現(xiàn)?
├─ 是 → 需要 virtual
└─ 否 → 可能不需要 virtual最佳實踐建議
- 設(shè)計時考慮:如果函數(shù)可能被重寫以擴(kuò)展行為,就聲明為
virtual - 使用
override:明確表達(dá)重寫意圖,編譯器可檢查 - 慎用純虛函數(shù):需要派生類必須實現(xiàn)時使用
= 0 - 性能考量:虛函數(shù)有輕微開銷,但通常可忽略
總結(jié)
判斷是否需要多態(tài)的三個要點:
- 是否通過基類指針/引用調(diào)用?
- 派生類是否需要擴(kuò)展基類行為?
- 是否需要統(tǒng)一接口但不同實現(xiàn)?
在這個菜單系統(tǒng)的案例中,三個條件都滿足,因此必須使用多態(tài)。通過將基類函數(shù)聲明為 virtual,確保了代碼的正確性和可擴(kuò)展性。
參考資料
- C++ 標(biāo)準(zhǔn)文檔關(guān)于虛函數(shù)的規(guī)定
- 《Effective C++》第33條:Make non-leaf classes abstract
- 《C++ Primer》第15章:面向?qū)ο缶幊?/li>
到此這篇關(guān)于C++ 多態(tài)性實戰(zhàn):何時使用 virtual 和 override?的文章就介紹到這了,更多相關(guān)C++ virtual 和 override內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Qt實現(xiàn)SqlRelationalTable關(guān)聯(lián)表組件
在Qt中我們可以通過拖拽的方式將不同組件放到指定的位置,實現(xiàn)圖形化開發(fā)極大的方便了開發(fā)效率,本章將重點介紹SqlRelationalTable關(guān)聯(lián)表組件的常用方法及靈活運用,感興趣的可以了解一下2023-12-12
詳解C語言中的char數(shù)據(jù)類型及其與int類型的轉(zhuǎn)換
這篇文章主要介紹了詳解C語言中的char數(shù)據(jù)類型及其與int類型的轉(zhuǎn)換,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-08-08
c語言中十進(jìn)制轉(zhuǎn)二進(jìn)制顯示小工具的實現(xiàn)代碼
本篇文章是對c語言中十進(jìn)制轉(zhuǎn)二進(jìn)制顯示小工具的實現(xiàn)代碼進(jìn)行了詳細(xì)的分析的介紹,需要的朋友參考下2013-05-05
一文搞懂C++中的四種強(qiáng)制類型轉(zhuǎn)換
很多朋友向小編了解C語言中怎么進(jìn)行強(qiáng)制類型轉(zhuǎn)換呢?在這小編告訴大家強(qiáng)制類型轉(zhuǎn)換可以分為兩種,一種是隱式類型轉(zhuǎn)換一種是顯示類型轉(zhuǎn)換,下面通過示例代碼給大家介紹下,需要的朋友參考下吧2021-07-07
Matlab實現(xiàn)黑洞優(yōu)化算法的示例代碼
根據(jù)黑洞現(xiàn)象原理首次提出BH 算法,它在傳統(tǒng)PSO基礎(chǔ)上引入了新的機(jī)制,有效地提高了收斂速度并防止了陷入局部極值的情況發(fā)生.本文將用Matlab實現(xiàn)這一算法,需要的可以參考一下2022-06-06
linux下C語言中的mkdir函數(shù)與rmdir函數(shù)
以下是對C語言中的mkdir函數(shù)與rmdir函數(shù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下2013-08-08

