C++繼承和動態(tài)內(nèi)存分配
文章轉(zhuǎn)自微信 公眾號:Coder梁(ID:Coder_LT)
1.簡介
這里面有一個問題,當(dāng)我們的基類使用動態(tài)內(nèi)存分配,并且重新定義賦值和復(fù)制構(gòu)造函數(shù),這會對派生類的實現(xiàn)有什么影響呢?
我們來看兩種情況:
2.派生類不用new
假設(shè)基類中使用了動態(tài)內(nèi)存分配:
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); };
在這個聲明里包含了構(gòu)造函數(shù)、析構(gòu)函數(shù)、復(fù)制構(gòu)造函數(shù)和重載賦值運算符。
現(xiàn)在假設(shè)我們從baseDMA
派生出了類lackDMA
,但是后者不使用new
:
class lackDMA: public baseMDA { ? ?private: ? ? ?char color[40]; ? ? public: ? ? ?... };
問題來了,我們要不要給lackDMA這個類定義析構(gòu)函數(shù)、復(fù)制構(gòu)造函數(shù)和賦值運算符呢?
答案是不需要。
首先是析構(gòu)函數(shù),這個很好想明白,如果我們沒有定義析構(gòu)函數(shù),那么編譯器會自動定義一個不執(zhí)行任何操作的默認(rèn)析構(gòu)函數(shù)。實際上派生類的析構(gòu)函數(shù)往往會在執(zhí)行一些邏輯之后調(diào)用基類的構(gòu)造函數(shù),因為lackDMA類中的成員不是通過new創(chuàng)建的,因此不需要額外的操作,所以默認(rèn)析構(gòu)函數(shù)是合適的。
同樣的默認(rèn)復(fù)制構(gòu)造函數(shù)也會執(zhí)行非new
創(chuàng)建成員的復(fù)制,所以對于color變量來說是沒問題的。并且在派生類當(dāng)中,默認(rèn)復(fù)制構(gòu)造函數(shù)除了會復(fù)制非new創(chuàng)建的成員之外,還會調(diào)用基類的復(fù)制構(gòu)造函數(shù)來復(fù)制父類成員的部分。所以,對于派生類lackDMA
來說,我們使用默認(rèn)的復(fù)制構(gòu)造函數(shù)一樣沒有問題。
賦值也是一樣的,默認(rèn)的賦值運算符也會自動使用基類的賦值運算符來對基類的成員進行賦值。
3.派生類使用new
我們再來看看派生類當(dāng)中使用了new
的情況。
class hasDMA: public baseMDA { ? ?private: ? ? ?char *style; ? ? public: ? ? ?... };
在hasDMA
這個類當(dāng)中,我們添加了一個需要使用new創(chuàng)建的char*成員。在這種情況下,我們就沒辦法使用默認(rèn)的函數(shù)了,就必須定義顯式析構(gòu)函數(shù)、復(fù)制構(gòu)造函數(shù)和賦值運算符了,我們一個一個來看。
首先是析構(gòu)函數(shù),派生類的析構(gòu)函數(shù)會自動調(diào)用基類的析構(gòu)函數(shù),所以我們只需要在析構(gòu)函數(shù)當(dāng)中釋放派生類中獨有的成員變量即可。
hasDMA::~hasDMA() { ? ? delete []style; }
然后我們再來看看拷貝構(gòu)造函數(shù),由于派生類不能訪問基類private
成員,所以我們需要調(diào)用基類的拷貝構(gòu)造函數(shù)。
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; }
這當(dāng)中有一個語句看起來有些奇怪:
baseDMA::operator=(hs);
這是我們手動顯式調(diào)用了基類的賦值運算符,我們直接用等于號賦值也有同樣的效果:
*this = hs;
為什么不這么干呢?這是因為編譯器在執(zhí)行的時候會默認(rèn)調(diào)用子類的賦值運算符hasDMA::operator=
,從而導(dǎo)致一直遞歸導(dǎo)致死循環(huán)。
所以我們需要手動寫明作用域解析符,表明這是調(diào)用的父類賦值運算符,而非派生類的運算符,這一點比較隱晦,要千萬注意。
到此這篇關(guān)于C++繼承和動態(tài)內(nèi)存分配的文章就介紹到這了,更多相關(guān)C++繼承和動態(tài)內(nèi)存分配內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言中字符型數(shù)據(jù)和浮點型數(shù)據(jù)介紹
大家好,本篇文章主要講的是C語言中字符型數(shù)據(jù)和浮點型數(shù)據(jù)介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽2022-01-01淺析結(jié)束程序函數(shù)exit, _exit,atexit的區(qū)別
在一個程序中最多可以用atexit()注冊32個處理函數(shù),這些處理函數(shù)的調(diào)用順序與其注冊的順序相反,也即最先注冊的最后調(diào)用,最后注冊的最先調(diào)用2013-09-09