拷貝構造函數 :
1概念
拷貝構造函數隻有單個形參,該形參是對本類類型對象的引用(常用const 修飾),
使用已存在的類類型的對象建立新對象時,編譯器自動調用該函數。
eg:
假如 Claa A{
public:A(const A& a){}
private :
int a;},
A a ,
A b(a);
2 特征
1 隻有一個參數: 引用傳參,傳值方式将會無限遞歸(Why)
傳值無限遞歸原因:傳值時拷貝構造函數的形參将會拷貝傳來的值,也是一個拷貝構造同時也是一個拷貝相當于A b(a);因為類并沒有正确實作引用,是以将在形參接收這裡無限遞歸下去。
另外,寫成傳值編譯器将會報錯
2 拷貝構造函數是構造函數的一個重載形式,(言下之意,構造函數還有别的函數重載形式)
3 若未進行顯式地定義拷貝構造函數,編譯器将隐式地生成一個拷貝構造函數,。今天我來補充一下,另一個構造的重載:C++11 提出的引用構造(右值引用) eg: string(string&& s )
4 .既然編譯器能自己生成預設的拷貝構造函數,那我們還要自己定義嗎?
答案是 肯定的。
理由:編譯器并不知道我們的類中是怎樣的成員,有沒有多次使用用一個類對象定義拷貝構造函數,假如說我們在類中 并沒有申請(管理)記憶體空間,那麼出類時,析構函數将會正常的銷毀類中的成員(空間資源),釋放記憶體。 但是, 請你想一想,假如你的類中 申請了空間(管理了記憶體空間),而你申請的空間被拷貝構造函數使用 (換句話說,就是假如拷貝構造函數使用了你申請的記憶體空間,并拷貝出了多個類 類型的對象),這會發生什麼?? 這會導緻你申請的空間被同時多個類類型對象共用(換句話說,多個類類型對象指向同一空間(同一對象)),而析構函數會銷毀你的所有成員,導緻同一申請的空間釋放多次,這當然不行了!!!
是以,我們顯式地寫個拷貝構造函數是很有必要的!(目前我能力還不行,但是道理我懂了,加油)
以下代碼為什麼會崩掉?留待以後回來看看
#include"iostream"
#include"string.h"
#include"stdio.h"
#include "windows.h"
using namespace std;
class String
{
public :
// 拷貝構造函數
String(const char* str = "Jack")
{
_str = (char*)malloc(strlen(str) + 1);
strcpy(_str, str);
}
//析構函數
~String()
{
cout <<"~String()"<< endl;
//printf("%s","~String()");
free(_str);
}
private:
char * _str;
};
int main(void)
{
String s1("hello");//調用編譯器預設生成的構造函數
String s2(s1);
system("pause");
return 0;
}
2 指派運算符重載
概念:什麼是指派運算符重載?
指派運算符重載就是:編譯器本來不支援該類型的運算,但是使用者想實作,所是以産生這個函數。
運算符重載是不是聽着就很不一樣??
它也是一種函數重載。
函數格式 : 傳回值類型 + operate +運算符(參數清單){函數體}
特征: operate 關鍵字後邊 + 運算符符号
注意: 1 不能自己建立新的運算符,運算符就是運算符,不是個别人定義的
2 參數清單必須至少有一個 枚舉類型或者類類型的對象
3 運算符的語義不允許更改 eg: 外部為 operate+(參數清單){return a-b;}
這樣是錯誤的!
4 若為類的成員的 (重載)函數,參數還有一個隐藏的this指針,即參數數量+1