一、派生類中不使用new
在派生類中不使用new意味着,派生類中新增加的成員沒有指針類型的成員。
(1)派生類中是否需要顯式的定義析構函數?
不需要。因爲在派生類中沒有指針成員,所以在派生類對象生命週期結束時,使用默認的派生類的析構函數也是可以釋放掉派生類中新增加的成員,然後調用基類的析構函數完成對派生類中繼承下來的成員的清理工作。
(2)派生類中是否需要顯式的定義拷貝構造函數?
不需要。因爲在派生類中沒有指針,所以在拷貝的過程中,先顯式的調用基類的拷貝構造函數,完成對派生類中從基類繼承的成員的複製,然後使用派生類的默認拷貝構造函數完成對派生類中新增成員的複製。
(3)派生類中是否需要顯式的定義賦值運算符重載函數?
不需要。因爲在派生類中沒有指針,所以在賦值的過程中,先顯式的調用基類的賦值運算符重載函數,完成對派生類中從基類繼承的成員的賦值,然後使用派生類的默認賦值運算符重載函數完成對派生類中新增成員的賦值。
二、派生類中使用new
假如在基類中使用了new,並且在派生類中同樣使用了new。
//基類的定義
class Base
{
private:
char* Base_str;
int len;
public:
Base(char* _str=nullptr,int _len);
virtual ~Base()
Base(const Base& b);
Base& operator =(const Base& b);
......
};
//派生類定義
class Derived:public Base
{
private:
char* Derived_str;
......
};
(1)派生類中是否需要顯式的定義析構函數?
需要。因爲在派生類中使用了new,所以此時如果我們僅僅調用默認的析構函數,那麼就無法將Derive_str
所指向的空間釋放掉。因此我們需要自己顯式的定義析構函數。如下所示:
//基類的析構
Base::~Base()
{
delete[] Base_str;
}
//派生類的析構
Derived::~Derived()
{
delete[] Derived_str;
}
這樣,當執行完派生類的析構後,再調用基類的析構就能完成對整個派生類對象的清理工作。
注意:派生類析構函數只是對新增加的成員進行清理工作,而從基類中繼承下來的成員則由基類的析構進行。
(2)派生類中是否顯式的定義拷貝構造?
需要。
//基類的拷貝構造
Bsse::Base(const Base& b)
{
Base_str=new char[strlen(b.Base_str)+1];
strcpy(Base_str,b.Base_str);
len=b.len;
}
//派生類的拷貝構造
Derived::Derived(const Derived& d):Base(d)
{
Derived_str=new char[strlen(b.Derived_str)+1];
strcpy(Derived_str,b.Derivede_str);
}
先調用基類的拷貝構造完成派生類中基類成員的拷貝,再調用派
生類的拷貝構造完成對派生類中新增成員的拷貝。
注意:
成員初始化列表將Derived
的引用傳遞給了Base
的構造函數。但是在Base類中沒有一個這樣可以接受Derived
引用類型的構造函數,那麼需不需定義一個專門接收這種類型的構造函數呢?答案是不需要,因爲拷貝構造函數,有一個Base
類型的引用,而派生類對象可以賦值給基類引用。因此Derived
引用將作爲實參傳遞給拷貝構造函數,然後利用拷貝構造函數構造新對象的基類部分。
(3)派生類中是否顯式的定義賦值運算符重載函數?
需要。
//基類的賦值運算符重載函數
Base& operator =(const Base& b)
{
if(this==&b)
return *this;
delete[] Base_str;
Base_str=new char[strlen(b.Base_str)+1];
strcpy(Base_str,b.Base_str);
len=b.len;
return *this;
}
//派生類的賦值運算符重載函數
Derived& operator =(const Derived& d)
{
if(this==&d)
return *this;
Base::operator=(d); //調用了基類的賦值函數
delete[] Derived_str;
Derived_str=new char[strlen(d.Derived_str)+1];
strcpy(Derived,d.Derived);
return *this;
}
總結
如果在派生類中沒有使用new,那麼可以不用顯式的定義析構函數、拷貝構造函數、賦值運算符重載函數。
如果在派生類中使用了new,那麼必須顯式的定義相應的析構函數、拷貝構造函數、賦值運算符重載函數。對於析構函數來說,由系統自動調用完成;對於拷貝構造函數來說,通過成員初始化列表中調用基類的拷貝構造函數來完成的;對於賦值運算符重載函數來說,是通過作用域解析運算符顯式的調用基類的賦值運算符重載函數來完成的。