建構函式,拷貝建構函式,解構函式,賦值函式
例一:
class CGoods
{
//行為,成員方法
public:
CGoods(char *name = NULL, int amount = 0, double price = 0.0) //建構函式
{
if (name == NULL)
{
mpName = new char[1];
*mpName = '\0';
}
else
{
mpName = new char[strlen(name) + 1];
strcpy(mpName, name);
}
mAmount = amount;
mPrice = price;
}
~CGoods() //解構函式
{
delete[]mpName;
mpName = NULL;
}
CGoods(const CGoods &src) //拷貝建構函式
{
mpName = new char[strlen(src.mpName) + 1];
strcpy(mpName, src.mpName);
mAmount = src.mAmount;
mPrice = src.mPrice;
}
void operator=(const CGoods &src) //賦值函式
{
if (this == &src)
return;
delete[]mpName;
mpName = NULL;
mpName = new char[strlen(src.mpName) + 1];
strcpy(mpName, src.mpName);
mAmount = src.mAmount;
mPrice = src.mPrice;
}
private:
char *mpName;
int mAmount;
double mPrice;
};
建構函式
沒有返回值、函式名字和類名稱必須一樣
建構函式可以帶引數,因此建構函式可以過載
當沒有提供任何建構函式的時候,編譯器會給類提供預設的建構函式,函式什麼也不做,是個空函式
解構函式
沒有返回值 不能帶引數 不能過載
拷貝建構函式
拷貝建構函式不能按值傳遞!!!
把形參複製到實參會呼叫拷貝建構函式。如果允許拷貝建構函式傳值,就會在拷貝建構函式內呼叫拷貝建構函式,形成永無休止的遞迴呼叫從而導致棧滿溢位。只能將建構函式修改為A(const A&other),即把傳值引數改為常量引用(傳指標也不可以,只能改為引用)
用物件初始化物件,預設做的拷貝方式是,按記憶體位元組拷貝過去,俗稱淺拷貝!
如果物件佔用了外部的資源,那麼預設的淺拷貝一定會發生問題的!所以,當預設的淺拷貝發生問題的時候,需要使用者自己提供相應的拷貝建構函式
如果物件預設的淺拷貝發生問題,那麼有哪些解決方案?
1。提供自定義的拷貝建構函式和賦值運算子的過載函式
2。把拷貝建構函式和賦值運算子的過載函式的宣告提供在private裡面
賦值函式
賦值步驟:
1,先排除自賦值;2,釋放原來的資源;3,重新開闢空間,賦值
例二:
OOP的迴圈佇列構造,析構,拷貝構造,賦值函式
class CQueue
{
public:
CQueue(int size = 10) //建構函式
{
mFront = mRear = 0;
mSize = size;
mpQueue = new int[mSize];
}
CQueue(const CQueue &src) //拷貝建構函式
{
cout << "CQueue(const CQueue &src)" << endl;
mFront = src.mFront;
mRear = src.mRear;
mSize = src.mSize;
mpQueue = new int[mSize];
for (int i = mFront; i != mRear; i = (i + 1) % mSize)
{
mpQueue[i] = src.mpQueue[i];
}
}
void operator=(const CQueue &src) //賦值函式
{
cout << "operator=" << endl;
// 先排除自賦值
if (this == &src)
{
return;
}
//釋放原來的資源
delete []mpQueue;
mpQueue = NULL;
//重新開闢空間,賦值
mFront = src.mFront;
mRear = src.mRear;
mSize = src.mSize;
mpQueue = new int[mSize];
for (int i = mFront; i != mRear; i = (i + 1) % mSize)
{
mpQueue[i] = src.mpQueue[i];
}
}
~CQueue() //解構函式
{
delete[]mpQueue;
mpQueue = NULL;
}
/*CQueue queue1 ; //queue1被初始化為queue,queue1析構後地址被釋放,queue指向變為野指標*/
/*對於物件的運算 =》 左邊物件呼叫成員方法,把右邊的物件當做引數傳入
queue2.operator=(queue1);
void operator=(const CQueue &src) */
物件的構造和析構:
1.物件的生成分兩步
a.給物件分配記憶體 b.呼叫建構函式構造物件 =》 物件產生了!!!
2.如果沒有提供任何建構函式,編譯器會產生預設建構函式,空函式;但是如果使用者提供
了任意建構函式,編譯器就不再產生預設構造函數了!
3.在呼叫預設建構函式的時候,不要新增()
4.棧上的物件,先構造,後析構;後構造,先析構
5.棧上的物件,定義的時候呼叫相應的建構函式;return處,要析構棧上的所有物件
例三:
class String
{
public:
String(const char*str = NULL) //普通建構函式
{
if (str == NULL)
{
m_data = new char[1];
*m_data = 0;
}
else
{
m_data = new char[strlen(str) + 1];
strcpy(m_data, str);
}
}
String(const String&other) //拷貝建構函式
{
m_data = new char[strlen(other.m_data) + 1];
strcpy(m_data,other.m_data);
}
~String() //解構函式
{
delete[]m_data;
m_data = NULL;
}
String &operator = (const String &other) //賦值函式
{
if (this == &other)
{
return *this;
}
delete[]&m_data;
m_data = NULL;
m_data = new char[strlen(other.m_data) + 1];
strcpy(m_data, other.m_data);
}
private:
char*m_data;
};
其他:
int *p = new int; //分配int整形大小的空間
int *p = new int();//分配int整形大小的空間並初始化0
int *p = new int(10);//分配int整形大小的空間並初始化10
int *p = new int[10]; 只開闢記憶體,10個大小為int整形的空間,不進行初始化
int *p = new int[10](); 不僅僅開闢記憶體,而且還初始化,int,陣列所有元素的初值為0
用臨時物件,拷貝構造新物件,此時臨時物件就被C++編譯器優化掉了
物件使用的三個優化規則:
1.函式引數傳遞物件,用引用傳遞,不要按值傳遞
2.如果你的函式返回的是物件的值,請返回一個臨時物件,不要返回一個
已經存在的物件
3.接收返回物件的函式,以初始化方式接收,不要用賦值方式接收