int a=100; int b=a;
#include<iostream>
using namespace std; class CExample { private: int a; public: //構造函數 CExample(int b) { a=b; printf("constructor is called\n"); } //拷貝構造函數 CExample(const CExample & c) { a=c.a; printf("copy constructor is called\n"); } //析構函數 ~CExample() { cout<<"destructor is called\n"; } void Show() { cout<<a<<endl; } }; int main() { CExample A(100); CExample B=A; B.Show(); return 0; }
#include<iostream>
using namespace std; class CExample { private: int a; public: CExample(int b) { a=b; printf("constructor is called\n"); } CExample(const CExample & c) { a=c.a; printf("copy constructor is called\n"); } ~CExample() { cout<<"destructor is called\n"; } void Show() { cout<<a<<endl; } }; void g_fun(CExample c) { cout<<"g_func"<<endl; } int main() { CExample A(100); CExample B=A; B.Show(); g_fun(A); return 0; }
#include<iostream>
using namespace std; class CExample { private: int a; public: //構造函數 CExample(int b) { a=b; printf("constructor is called\n"); } //拷貝構造函數 CExample(const CExample & c) { a=c.a; printf("copy constructor is called\n"); } //析構函數 ~CExample() { cout<<"destructor is called\n"; } void Show() { cout<<a<<endl; } }; CExample g_fun() { CExample temp(0); return temp; } int main() { g_fun(); return 0; }
CExample A(100); CExample B=A;
Rect::Rect(const Rect& r) { width=r.width; height=r.height; }
#include<iostream>
using namespace std; class Rect { public: Rect() { count++; } ~Rect() { count--; } static int getCount() { return count; } private: int width; int height; static int count; }; int Rect::count=0; int main() { Rect rect1; cout<<"The count of Rect:"<<Rect::getCount()<<endl; Rect rect2(rect1); cout<<"The count of Rect:"<<Rect::getCount()<<endl; return 0; }
這段代碼對前面的類,加入了一個靜態成員,目的是進行計數。在主函數中,首先建立對象rect1,輸出此時的對象個數,而後使用rect1複製出對象rect2,再輸出此時的對象個數,按照理解,此時應該有兩個對象存在,但實際程序運行時,輸出的都是1,反應出只有1個對象。此外,在銷燬對象時,因爲會調用銷燬兩個對象,類的析構函數會調用兩次,此時的計數器將變爲負數。html
說白了,就是拷貝構造函數沒有處理靜態數據成員。ios
出現這些問題最根本就在於在複製對象時,計數器沒有遞增,咱們從新編寫拷貝構造函數,以下:面試
#include<iostream>
using namespace std; class Rect { public: Rect() { count++; } Rect(const Rect& r) { width=r.width; height=r.height; count++; } ~Rect() { count--; } static int getCount() { return count; } private: int width; int height; static int count; }; int Rect::count=0; int main() { Rect rect1; cout<<"The count of Rect:"<<Rect::getCount()<<endl; Rect rect2(rect1); cout<<"The count of Rect:"<<Rect::getCount()<<endl; return 0; }
2. 淺拷貝函數
所謂淺拷貝,指的是在對象複製時,只對對象中的數據成員進行簡單的賦值,默認拷貝構造函數執行的也是淺拷貝。大多狀況下「淺拷貝」已經能很好地工做了,可是一旦對象存在了動態成員,那麼淺拷貝就會出問題了,讓咱們考慮以下一段代碼:ui
#include<iostream>
#include<assert.h>
using namespace std; class Rect { public: Rect() { p=new int(100); } ~Rect() { assert(p!=NULL); delete p; } private: int width; int height; int *p; }; int main() { Rect rect1; Rect rect2(rect1); return 0; }
在這段代碼運行結束以前,會出現一個運行錯誤。緣由就在於在進行對象複製時,對於動態分配的內容沒有進行正確的操做。咱們來分析一下:spa
在運行定義rect1對象後,因爲在構造函數中有一個動態分配的語句,所以執行後的內存狀況大體以下:.net
#include<iostream>
#include<assert.h>
using namespace std; class Rect { public: Rect() { p=new int(100); } Rect(const Rect& r) { width=r.width; height=r.height; p=new int(100); *p=*(r.p); } ~Rect() { assert(p!=NULL); delete p; } private: int width; int height; int *p; }; int main() { Rect rect1; Rect rect2(rect1); return 0; }
3. 防止默認拷貝發生unix
經過對對象複製的分析,咱們發現對象的複製大多在進行「值傳遞」時發生,這裏有一個小技巧能夠防止按值傳遞——聲明一個私有拷貝構造函數。甚至沒必要去定義這個拷貝構造函數,這樣由於拷貝構造函數是私有的,若是用戶試圖按值傳遞或函數返回該類對象,將獲得一個編譯錯誤,從而能夠避免按值傳遞或返回對象。指針
//防止按值傳遞 class CExample { private: int a; public: //構造函數 CExample(int b) { a = b; cout<<"creat: "<<a<<endl; } private: //拷貝構造函數,只是聲明 CExample(const CExample& C); public: ~CExample() { cout<< "delete: "<<a<<endl; } void Show () { cout<<a<<endl; } }; //???? void g_Fun(CExample C) { cout<<"test"<<endl; } int main() { CExample test(1); //g_Fun(test); //按值傳遞將出錯 return 0; }
當出現類的等號賦值時,會調用拷貝函數,在未定義顯示拷貝構造函數的狀況下,系統會調用默認的拷貝函數——即淺拷貝,它可以完成成員的一一複製。當數據成員中沒有指針時,淺拷貝是可行的。但當數據成員中有指針時,若是採用簡單的淺拷貝,則兩類中的兩個指針將指向同一個地址,當對象快結束時,會調用兩次析構函數,而致使指針懸掛現象。因此,這時,必須採用深拷貝。code
深拷貝與淺拷貝的區別就在於深拷貝會在堆內存中另外申請空間來儲存數據,從而也就解決了指針懸掛的問題。簡而言之,當數據成員中有指針時,必需要用深拷貝。
5. 拷貝構造函數裏能調用private成員變量嗎?
解答:這個問題是在網上見的,當時一會兒有點暈。其時從名子咱們就知道拷貝構造函數其時就是一個特殊的構造函數,操做的仍是本身類的成員變量,因此不受private的限制。
X::X(const X&); //拷貝構造函數 X::X(X); X::X(X&, int a=1); //拷貝構造函數 X::X(X&, int a=1, int b=2); //拷貝構造函數
class X { public: X(const X&); // const 的拷貝構造 X(X&); // 非const的拷貝構造 };