搬運(yùn)自大神博客
題目
為下面的Rectangle類實(shí)現(xiàn)構(gòu)造函數(shù)莹桅,拷貝構(gòu)造函數(shù)昌执,賦值操作符烛亦,析構(gòu)函數(shù)。
class Shape
{
int no;
};
class Point
{
int x;
int y;
};
class Rectangle: public Shape
{
int width;
int height;
Point * leftUp;
public:
Rectangle(int width, int height, int x, int y);
Rectangle(const Rectangle& other);
Rectangle& operator=(const Rectangle& other);
~Rectangle();
};
解析
構(gòu)造函數(shù)
- 盡量使用初始化列表懂拾;
- 對leftUp指針的構(gòu)造煤禽,leftUp指向一個(gè)Point對象,構(gòu)造函數(shù)需要在堆內(nèi)生成一個(gè)新的point對象岖赋,并用leftUp指向該對象
inline
Rectangle::Rectangle(int width, int height, int x, int y):width(width),height(height),leftUp(new Point(x,y)){}
//盡量使用初始化列表檬果,包括對leftUp的初始化
拷貝構(gòu)造函數(shù)
- 盡量使用初始化列表
- 注意對父類繼承而來的no的拷貝構(gòu)造,方法是調(diào)用父類shape的拷貝構(gòu)造函數(shù) Shape(other)
- 對this->leftUp的拷貝構(gòu)造唐断,調(diào)用Point的拷貝構(gòu)造函數(shù)选脊,這樣在Point內(nèi)部有變化時(shí),避免大量修改脸甘。
this->leftUp = new Point(*other.leftUp);
- 針對other.leftUp是否為空的討論恳啥,空指針情況沒必要在堆內(nèi)生成對象,同時(shí)當(dāng)other.leftUp為空時(shí)丹诀,this->leftUp初始默認(rèn)是隨機(jī)值钝的,要對他進(jìn)行賦值為空指針。
完整的拷貝構(gòu)造函數(shù):
inline
Rectangle::Rectangle(const Rectangle& other):Shape(other),width(other.width),height(other.height){
if(other.leftUp!=NULL)
this->leftUp = new Point(*other.leftUp);
else
this->leftUp = NULL;
}
賦值操作符
- 賦值操作符往往需要首先判定自己給自己復(fù)制的情況忿墅,避免內(nèi)存泄漏
- 調(diào)用父類的賦值操作符扁藕,完成對父類繼承部分的賦值操作,方法如下:
Shape::operator=(other); //調(diào)用父類的賦值操作符疚脐,完成對父類繼承部分的賦值操作
- 需要對lefrUp, other.leftUp是否為空進(jìn)行討論
- other.leftUp為空時(shí)亿柑,直接釋放this->leftUp空間,并將其賦為空即可棍弄;
- other.leftUp不為空時(shí)望薄,
- 若this->leftUp也不為空,則直接將other->leftUp指向的內(nèi)容賦值給this->leftUp指向的內(nèi)容即可呼畸;
- 若this->leftUp為空痕支,創(chuàng)建新的Point對象
Rectangle& Rectangle::operator= (const Rectangle& other){
if(this == &other){ //賦值操作符往往需要首先判定自己給自己賦值的情況,避免內(nèi)存泄露
return *this;
}
Shape::operator=(other); //調(diào)用父類的賦值操作符蛮原,完成對父類繼承部分的賦值操作
this->width = other.width;
this->height = other.height;
if(other.leftUp != NULL){
if(leftUp != NULL) {
*leftUp = *other.leftUp; //不必刪除leftUp再重新構(gòu)建卧须,直接進(jìn)行賦值即可(解指針,調(diào)用point類的賦值操作符即可)
}
else{
leftUp = new Point(*other.leftUp); //leftUp為空儒陨,不能解指針花嘶,需要?jiǎng)?chuàng)建一個(gè)新對象
}
}
else{
delete leftUp;
this->leftUp = NULL;
}
return *this;
}
析構(gòu)函數(shù)
Rectangle:: ~Rectangle(){
delete leftUp;
}
整體代碼和其他注意事項(xiàng)
- Rectangle賦值構(gòu)造函數(shù),構(gòu)造順序:先父類蹦漠,后按照子類中聲明的順序椭员,與初始化列表中的順序無關(guān)。
- 正確區(qū)分拷貝構(gòu)造函數(shù)和賦值操作符
拷貝構(gòu)造函數(shù)是構(gòu)造函數(shù)笛园,也就是創(chuàng)建新對象時(shí)隘击,所以一個(gè)對象存在侍芝,一個(gè)對象尚未存在;
賦值操作符使用時(shí)埋同,兩個(gè)對象必然都是存在的州叠,所以需要討論的問題是是否自我賦值等 -
面對此類問題方法:先忘掉語法,畫內(nèi)存模型莺禁,本例即:
內(nèi)存模型.jpg
然后寫的時(shí)候分析指針是否為空留量;
拷貝構(gòu)造就是一邊有,一邊沒有哟冬;賦值操作符就是兩邊都有楼熄。
class Shape
{
int no;
};
class Point
{
private:
int x;
int y;
public:
Point(int x,int y):x(x),y(y){}
};
class Rectangle: public Shape
{
int width;
int height;
Point* leftUp;
public:
Rectangle(int width, int height, int x, int y);
Rectangle(const Rectangle& other);
Rectangle& operator=(const Rectangle& other);
~Rectangle();
};
inline
Rectangle::Rectangle(int width,int heigt, int x,int y):width(width),height(height),leftUp(new Point(x,y)){}
//盡量使用初始化列表,包括對leftUp的初始化
inline
Rectangle::Rectangle(const Rectangle& other)
:Shape(other),width(other.width),height(other.height){ // 注意對繼承而來對象no的拷貝構(gòu)造浩峡,通過調(diào)用父類的拷貝構(gòu)造函數(shù)
if(other.leftUp != NULL){ //針對other.leftUp是否為空的討論可岂,空指針情況沒必要在堆內(nèi)生成對象
this->leftUp = new Point(*other.leftUp); //調(diào)用Point的拷貝構(gòu)造函數(shù),這樣在Point內(nèi)部有變化時(shí)翰灾,避免大量修改缕粹。
}
else{
this->leftUp = NULL; //leftUp初始默認(rèn)是隨機(jī)值,要對他進(jìn)行賦值為空指針纸淮。
}
}
Rectangle& Rectangle::operator= (const Rectangle& other){
if(this == &other){ //賦值操作符往往需要首先判定自己給自己賦值的情況平斩,避免內(nèi)存泄露
return *this;
}
Shape::operator=(other); //調(diào)用父類的賦值操作符,完成對父類繼承部分的賦值操作
this->width = other.width;
this->height = other.height;
if(other.leftUp != NULL){
if(leftUp != NULL) {
*leftUp = *other.leftUp; //不必刪除leftUp再重新構(gòu)建咽块,直接進(jìn)行賦值即可(解指針枷畏,調(diào)用point類的賦值操作符即可)
}
else{
leftUp = new Point(*other.leftUp); //leftUp為空卖丸,不能解指針,需要?jiǎng)?chuàng)建一個(gè)新對象
}
}
else{
delete leftUp;
this->leftUp = NULL;
}
return *this;
}
Rectangle:: ~Rectangle(){
delete leftUp;
}