網站首頁 編程語言 正文
文章轉自微信 公眾號:Coder梁(ID:Coder_LT)
1.簡介
這里面有一個問題,當我們的基類使用動態內存分配,并且重新定義賦值和復制構造函數,這會對派生類的實現有什么影響呢?
我們來看兩種情況:
2.派生類不用new
假設基類中使用了動態內存分配:
class baseDMA { ?private: ? ? ?char *label; ? ? ?int rating; ? ? public: ? ? ?baseDMA(const char* l="null", int r=0); ? ? ?baseDMA(const baseDMA& rs); ? ? ?virtual ~baseDMA(); ? ? ?baseDMA &operator=(const baseDMA& rs); };
在這個聲明里包含了構造函數、析構函數、復制構造函數和重載賦值運算符。
現在假設我們從baseDMA
派生出了類lackDMA
,但是后者不使用new
:
class lackDMA: public baseMDA { ? ?private: ? ? ?char color[40]; ? ? public: ? ? ?... };
問題來了,我們要不要給lackDMA這個類定義析構函數、復制構造函數和賦值運算符呢?
答案是不需要。
首先是析構函數,這個很好想明白,如果我們沒有定義析構函數,那么編譯器會自動定義一個不執行任何操作的默認析構函數。實際上派生類的析構函數往往會在執行一些邏輯之后調用基類的構造函數,因為lackDMA類中的成員不是通過new創建的,因此不需要額外的操作,所以默認析構函數是合適的。
同樣的默認復制構造函數也會執行非new
創建成員的復制,所以對于color變量來說是沒問題的。并且在派生類當中,默認復制構造函數除了會復制非new創建的成員之外,還會調用基類的復制構造函數來復制父類成員的部分。所以,對于派生類lackDMA
來說,我們使用默認的復制構造函數一樣沒有問題。
賦值也是一樣的,默認的賦值運算符也會自動使用基類的賦值運算符來對基類的成員進行賦值。
3.派生類使用new
我們再來看看派生類當中使用了new
的情況。
class hasDMA: public baseMDA { ? ?private: ? ? ?char *style; ? ? public: ? ? ?... };
在hasDMA
這個類當中,我們添加了一個需要使用new創建的char*成員。在這種情況下,我們就沒辦法使用默認的函數了,就必須定義顯式析構函數、復制構造函數和賦值運算符了,我們一個一個來看。
首先是析構函數,派生類的析構函數會自動調用基類的析構函數,所以我們只需要在析構函數當中釋放派生類中獨有的成員變量即可。
hasDMA::~hasDMA() { ? ? delete []style; }
然后我們再來看看拷貝構造函數,由于派生類不能訪問基類private
成員,所以我們需要調用基類的拷貝構造函數。
hasDMA::hasDMA(const hasDMA& hs): baseDMA(hs) { ? ? style = new char[std::strlen(hs.style) + 1]; ? ? std::strcpy(style, hs.style); }
最后是賦值運算符,同樣,由于派生類不能訪問基類中私有成員,我們也需要借助基類的賦值運算符:
hasDMA &hasDMA::operator(const hasDMA& hs) { ? ? if (this == &hs) return *this; ? ? baseDMA::operator=(hs); ? ? delete []style; ? ? style = new char[std::strlen(hs.style) + 1]; ? ? std::strcpy(style, hs.style); ? ? return *this; }
這當中有一個語句看起來有些奇怪:
baseDMA::operator=(hs);
這是我們手動顯式調用了基類的賦值運算符,我們直接用等于號賦值也有同樣的效果:
*this = hs;
為什么不這么干呢?這是因為編譯器在執行的時候會默認調用子類的賦值運算符hasDMA::operator=
,從而導致一直遞歸導致死循環。
所以我們需要手動寫明作用域解析符,表明這是調用的父類賦值運算符,而非派生類的運算符,這一點比較隱晦,要千萬注意。
相關推薦
- 2022-01-12 nvm-windows使用與避坑指南,npm沒反應也不報錯怎么辦
- 2021-12-06 Ubuntu編譯內核模塊,內容體現系統日志中_Linux
- 2022-06-25 C#實現連接電子秤串口自動稱重_C#教程
- 2023-07-15 es6中export和export default的區別
- 2022-04-16 C#基于Socket實現多人聊天功能_C#教程
- 2022-11-19 Python?numpy?ndarray屬性,索引,切片_python
- 2022-08-07 pd.drop_duplicates刪除重復行的方法實現_python
- 2022-11-16 從Context到go設計理念輕松上手教程_Golang
- 最近更新
-
- 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同步修改后的遠程分支