拷貝建構函式的3種呼叫情況分析( C++ )
阿新 • • 發佈:2018-12-19
拷貝建構函式的3種呼叫情況分析
目錄
什麼是拷貝建構函式?
- 拷貝建構函式 是一種特殊的建構函式,具有單個形參,該形參( 常用const修飾 )是對該類型別的引用。
- 如果在類中沒有定義拷貝建構函式,編譯器會自行定義一個。如果類帶有指標變數
,並有動態記憶體分配,為了防止淺拷貝帶來的風險,則它必須有一個拷貝建構函式。拷貝建構函式的最常見形式如下:
classname (const classname &obj)
{
// 建構函式的主體
}
- 這裡建構函式傳入的值為什麼需要是引用呢?個人第一反應:為了減少一次記憶體拷貝。其實這樣說是不完整的。眾說周知,函式的值傳遞有隱式地呼叫建構函式以實現臨時引數的初始化,呼叫
classname obj = aaa
;,又因為obj之前沒有被建立,所以又需要呼叫拷貝建構函式,故而又執行classname obj = aaa
,就這樣永遠的遞迴呼叫下去了。所以, 拷貝建構函式是必須要帶引用型別的引數的, 而且這也是編譯器強制性要求的。 這裡為什麼傳引數需宣告為
const
, 如果在函式中不會改變引用型別引數的值,加不加const
的效果是一樣的。而且不加const
,編譯器也不會報錯。但是為了整個程式的安全,還是加上const,防止對引用型別引數值的意外修改。使用拷貝建構函式的三種情況為:
- 一個物件需要通過另外一個物件進行初始化
- 一個物件以值傳遞的方式傳入函式體
- 一個物件以值傳遞的方式從函式返回
下面對這三種情況做一下簡介
一個物件需要通過另外一個物件進行初始化
#include <iostream>
using namespace std ;
class Line
{
public:
int getLength( void );
Line( int len ); // 簡單的建構函式
Line( const Line &obj); // 拷貝建構函式
~Line(); // 解構函式
private:
int *ptr;
};
// 成員函式定義,包括建構函式
Line::Line(int len)
{
cout << "呼叫建構函式" << endl;
// 為指標分配記憶體
ptr = new int;
*ptr = len;
}
Line::Line(const Line &obj)
{
cout << "呼叫拷貝建構函式併為指標 ptr 分配記憶體" << endl;
ptr = new int;
*ptr = *obj.ptr; // 拷貝值
}
Line::~Line(void)
{
cout << "釋放記憶體" << endl;
delete ptr;
}
int Line::getLength( void )
{
return *ptr;
}
void display(Line obj)
{
cout << "line 大小 : " << obj.getLength() <<endl;
}
// 程式的主函式
int main( )
{
Line line1(10);//這裡會呼叫一次建構函式
Line line2 = line1; // 這裡也呼叫了拷貝建構函式
display(line1);
display(line2);
return 0;
}
呼叫建構函式
呼叫拷貝建構函式併為指標 ptr 分配記憶體
呼叫拷貝建構函式併為指標 ptr 分配記憶體
line 大小 : 10
釋放記憶體
呼叫拷貝建構函式併為指標 ptr 分配記憶體
line 大小 : 10
釋放記憶體
釋放記憶體
釋放記憶體
一個物件以值傳遞的方式傳入函式體
#include <iostream>
using namespace std;
class Line
{
public:
int getLength( void );
Line( int len ); // 簡單的建構函式
Line( const Line &obj); // 拷貝建構函式
~Line(); // 解構函式
private:
int *ptr;
};
// 成員函式定義,包括建構函式
Line::Line(int len)
{
cout << "呼叫建構函式" << endl;
// 為指標分配記憶體
ptr = new int;
*ptr = len;
}
Line::Line(const Line &obj)
{
cout << "呼叫拷貝建構函式併為指標 ptr 分配記憶體" << endl;
ptr = new int;
*ptr = *obj.ptr; // 拷貝值
}
Line::~Line(void)
{
cout << "釋放記憶體" << endl;
delete ptr;
}
int Line::getLength( void )
{
return *ptr;
}
void display(Line obj/*這裡會呼叫一次拷貝建構函式*/)
{
cout << "line 大小 : " << obj.getLength() <<endl;
}
// 程式的主函式
int main( )
{
Line line(10);//這裡會呼叫一次建構函式
display(line);
return 0;
}
呼叫建構函式
呼叫拷貝建構函式併為指標 ptr 分配記憶體
line 大小 : 10
釋放記憶體
釋放記憶體
一個物件以值傳遞的方式從函式返回
#include <iostream>
using namespace std;
class Line
{
public:
int getLength(void);
Line(int len); // 簡單的建構函式
Line(const Line &obj); // 拷貝建構函式
Line returnLine(int i);
~Line(); // 解構函式
private:
int *ptr;
};
// 成員函式定義,包括建構函式
Line::Line(int len)
{
cout << "呼叫建構函式" << endl;
// 為指標分配記憶體
ptr = new int;
*ptr = len;
}
Line::Line(const Line &obj)
{
cout << "呼叫拷貝建構函式併為指標 ptr 分配記憶體" << endl;
ptr = new int;
*ptr = *obj.ptr; // 拷貝值
}
Line::~Line(void)
{
cout << "釋放記憶體" << endl;
delete ptr;
}
Line Line::returnLine(int i)
{
Line line(1);//這裡會呼叫一次建構函式
return line;//這裡會呼叫一次拷貝建構函式
}
int Line::getLength(void)
{
return *ptr;
}
// 程式的主函式
int main()
{
Line line1(10);
line1.returnLine(2);
system("pause");
return 0;
}
結果
呼叫建構函式
呼叫建構函式
呼叫拷貝建構函式併為指標 ptr 分配記憶體
釋放記憶體
釋放記憶體