復制構造函數
形如className :: className(const &) / className :: className(const className &)后者能以常量對象作為參數
如不寫復制構造函數,則編譯器默認提供,為了完成對象的復制功能
它起作用有三個工作環境:
1.一個對象初始化另一個同類的對象
1 Simple c2(c1); 2 Simple c2 = c1;//初始化
2.如果某函數有一個參數是類的一個對象,那么該函數被調用時,類的復制構造函數被調用
1 Simple A 2 { 3 pbulic: 4 A(){}; 5 A(A & a) 6 { 7 cout<<.....<<endl; 8 } 9 }; 10 void Fun(A a1){} 11 int main() 12 { 13 A a; 14 Fun(a);//.....
15 return 0; 16 }
3.如果函數的返回值是類的對象時,則函數返回是,類的復制構造函數被調用
1 class Simple 2 { 3 pbulic: 4 int x; 5 Simple(int n){x = n;}; 6 Simple(const Simple & a) 7 { 8 x = a.x; 9 cout<<"Copy constructor called"<<endl; 10 } 11 }; 12 Simple Fun() 13 { 14 Simple b(100); 15 return b;//作為復制構造函數的參數
16 } 17 int main() 18 { 19 cout<<Fun().x<<endl;// Copy constructor called 100
20 return 0; 21 }
注意:對象間的賦值不導致復制構造函數的調用
A c1,c2;
c2 = c1 ;//不會調用
A C3(C1);//這是初始化操作,會調用賦值構造函數
在函數參數列表中,為節省開銷,不引發復制構造函數的調用,使用ClassName & 引用類型為參數,
又為了確保實參值不變,再在引用前加上const關鍵字。復制構造函數往往加const和&,具體可以點這里
類型轉換構造函數
它的目的是實現類型的自動轉換,並且只有一個參數。當需要的時候,編譯系統會自動調用轉換構造函數,建立
一個無名的臨時對象(或臨時變量)。
1 class Complex 2 { 3 public: 4 double real, imag; 5 Complex( int i) 6 {//類型轉換構造函數
7 cout << "IntConstructor called" << endl; 8 real = i; imag = 0; 9 } 10 Complex(double r,double i) {real = r; imag = i; } 11 }; 12 int main () 13 { 14 Complex c1(7,8); 15 Complex c2 = 12; 16 c1 = 9; // 9被自動轉換成一個臨時Complex對象
17 cout << c1.real << "," << c1.imag << endl; 18 return 0; 19 }
1 class Complex 2 { 3 public: 4 double real, imag; 5 explicit Complex( int i) 6 {//顯式類型轉換構造函數
7 cout << "IntConstructor called" << endl; 8 real = i; imag = 0; 9 } 10 Complex(double r,double i) {real = r; imag = i; } 11 }; 12 int main () 13 { 14 Complex c1(7,8); 15 Complex c2 = Complex(12); 16 c1 = 9; // error, 9不能被自動轉換成一個臨時Complex對象
17 c1 = Complex(9) //ok
18 cout << c1.real << "," << c1.imag << endl; 19 return 0; 20 }
析構函數:~類名(){}
它沒有返回值和參數,一個類對應一個析構函數,在類的對象消亡時自動調用,也可以手動調用進行對象消亡的善后工作。如果懶的去寫,編譯器自動會生成缺省析構函數,但是什么也不做,如果寫了,就不自動生成了。
1 class Simple 2 { 3 private : 4 char * p; 5 public: 6 Simple() 7 { 8 p = new char[10]; 9 } 10 ~ Simple () ; 11 }; 12 Simple ::~ Simple() 13 { 14 delete [] p; 15 }
在對一個對象進行delete時,調用一次析構函數,在delete[]對象數組時,會調用n次析構函數,取決於數組大小。此外:
1 class CMyclass 2 { 3 public: 4 ~CMyclass() { cout << "destructor" << endl; } 5 }; 6 CMyclass obj; 7 CMyclass fun(CMyclass sobj ) 8 { //參數對象消亡也會導致析 9 //構函數被調用
10 return sobj; //函數調用返回時生成臨時對象返回
11 } 12 int main() 13 { 14 obj = fun(obj); //函數調用的返回值(臨時對象)被
15 return 0; //用過后,該臨時對象析構函數被調用
16 } 17 //destructor形參對象消亡 18 //destructor臨時對象消亡 19 //destructor全局對象消亡
new出來的對象或對象數組,不delete就不會消亡,就不會調用析構函數!!不是new出來的,則在生命期結束會自動調用
關於引用:引用是C++有的,C所沒有的,標志為 &,即C的取地址符。它的聲明為這樣
1 int n = 4; 2 int & r = n; //r為 int & 類型
其中r和n指向同一片地址空間 ,對 r和n的修改都會改變原來是4的那個值,相當於為n取了個別名r
在定義引用時一定要將其初始化成引用某個變量。並且之后不會引用別的變量
只能引用變量,不能引用常量和表達式
一個簡單而又形象的,見得次數很多的例子:交換元素
1 void swap( int * a, int * b) 2 { 3 int tmp; 4 tmp = * a; 5 * a = * b; 6 * b = tmp; 7 } 8 int n1, n2; 9 swap(& n1,& n2) ; // n1,n2的值被交換
1 //用了引用 2 void swap( int & a, int & b) 3 { 4 int tmp; 5 tmp = a; 6 a = b; 7 b = tmp; 8 } 9 int n1, n2; 10 swap(n1,n2) ; // n1,n2的值被交換
1 //en ..交換還可以這樣寫,當然遠不如swap(a,b)寫的快哈
2 int a = 3; 3 int b = 5; 4 a = a + b; 5 b = a - b; 6 a = a - b; 7 cout<<a<<" "<<b<<endl; 8 a = a ^ b; 9 b = a ^ b; 10 a = a ^ b; 11 cout<<a<<" "<<b<<endl;
引用還可以作為函數的返回值
1 int n = 4; 2 int & SetValue() 3 { 4 return n; 5 } 6 int main() 7 { 8 SetValue() = 40; 9 cout << n;return 0; 10 } //輸出: 40
關於常引用:
int n;
const int & r = n;
r = 10;//error 不能通過常引用r改變n的值
n = 30;//n的值可以變化
const T & 和T & 是不同的類型!!!
T & 類型的引用或T類型的變量可以用來初始化const T & 類型的引用。
int n = 8;
int & r1 = n;
const int r2 = r1;//初始化const T & 類型的引用。
const T 類型的常變量和const T & 類型的引用則不能用來初始化T &類型的引用,
除非進行強制類型轉換
常量指針:
1 //1.
2 int n,m 3 const int * p = n;//常量指針
4 *p = 5//error 不可以通過修改常量指針修改指向的內容
5 n = 5;//ok
6 p = & m;//ok 常量指針可以指向別的內容 7
8 //2.不可以把常量指針賦值給非常量指針(強轉可以),反之可以
9 const int * p; 10 int * p2; 11 p1 = p2; //ok
12 p2 = p1; //error
13 p2 = (int * ) p1; //ok,強制類型轉換
指針常量:
1 int a,b; 2 int const *p = & a; 3 * p = 9;//通過指針修改所指向的內容,ok
4 p = & b;//error 不可更改所指向的地址
這兩個不要搞混淆了。。。。
簡單的記憶,抓住第一個是常量在前,就意味着整個后面的地址內容是個常量,不可以通過指針去修改它,但是指向誰是可以變的;指針常量,這個常量在指針后面,表明這個指針所指向的地址不能變了,但你可以用它修改地址所對應的內容。。
動態內存分配:
變量: int * px = new int; //大小為sizeof(int)
數組: int * pn = new int[20];
釋放動態分配的內存:
int * px = new int;
delete px;//只能刪除一次
//數組
int * pn = new int[20];
delete [] pn;