1. 程式人生 > >C++中拷貝建構函式、淺拷貝與深拷貝的詳解

C++中拷貝建構函式、淺拷貝與深拷貝的詳解

拷貝建構函式呼叫時機:

1、物件需要通過另外一個物件進行初始

化:

     T t1(10, 20);T t2(0, 0);T t3 = t1; // 拷貝建構函式呼叫的時機一:T t4(t2);  // 拷貝建構函式呼叫的時機 二:

2、實參傳遞給形參時呼叫賦值建構函式 拷貝建構函式呼叫的時機三:

class T
{
public:
	T(int m, int n)
	{
		cout << "gouzao" << endl;
		a = m;
		b = n;
		c = 'q';
	}
	T(const T& obj)
	{
		cout << "fuzhi" << endl;
		a = obj.a + 10;
		b = obj.b - 5;
		c = obj.c;

	}
	~T()
	{
		cout << "xigou" << endl;
	}

	int a;
	int  b;
	char c;
	int get_A()
	{
		return  a;
	} 
	int get_B()
	{
		return  b;
	}
	
};
void f(T t)
{
	t.a = 100;
	t.b = 102;

}
void main()

{f(t1)};

3 返回匿名物件時,物件以值傳遞的方式從函式返回

T  go()//
{
T A(100,102);

return A;  //返回匿名物件
}

//匿名物件的去和留
//如果用匿名物件初始化一個同類型的物件,匿名物件轉化為有名物件 T m1=go();該物件的生命週期結束時才析構
//如果用匿名物件賦值 給另一個同類型的物件,匿名物件立即被析構  T m2(10,9);m2=go()

二:

淺拷貝與深拷貝 解析:

#define  _CRT_SECURE_NO_WARNINGS

#include<iostream>

#include<string>

using

 namespace std;

class Name

{

public:

Name(const char*myp)

{

len = strlen(myp);

p = (char*)malloc(len+1);

strcpy(p,myp);

}

~Name()

{

if (p != NULL)

free(p);

p = NULL;

len = 0;

}

private:

char* p;

int len;

};

void mainplay()

{

Name obj1("abcdef");

Name obj2 = obj1;//問題:在執行這句話時,當函式體結束時,要析構物件(且析構兩次),同一個記憶體地址被同時free兩次,所以會出錯

//用obj1來初始化obj2,要執行拷貝建構函式

//由於自己沒有定義拷貝建構函式,所以編譯器會自動呼叫預設的拷貝建構函式,編譯器提供的預設的拷貝建構函式是淺拷貝

//淺拷貝是指:只賦值了指標的值,而指標所指向的記憶體空間的內容沒有被賦值,淺拷貝的結果是obj1和obj2同時指向了同一個記憶體空間

編譯器提供的預設的拷貝建構函式,就是把指標的值(即obj的屬性值 char* p,int len)賦值給obj2,而並沒有開闢一個新的記憶體空間,把記憶體空間的內容(abcdefg)賦值給obj2.所以導致同一個記憶體空間被同時析構兩次時出錯,

解決方案:  深拷貝建構函式自己寫拷貝建構函式,在開闢一個新的 記憶體空間,然後把空間中內容拷貝到新的記憶體空間

Name(const Name&obj)

{

len = strlen(obj.p);

p = (char*)malloc(len + 1);

strcpy(p,obj.p);

}

Name obj3("obj3");

obj3 = obj1;

}

Obj1和obj3指向了統一記憶體空間,使程式崩潰。

解決等號運算子與淺拷貝帶來的問題方法就是:過載等號運算子,在函式中重新開闢一段記憶體空間為obj3物件所用,但是由於之前obj3已經開闢了記憶體空間,為了防止記憶體洩漏,,需要先對記憶體空間進行釋放,然後再重新建新的記憶體空間。

Name& operator=(Name&obj)

{

if (p != NULL)

{

delete[] p;

p = NULL;

len = 0;

}

p = (char*)malloc(strlen(obj.p)+1);

if (p != NULL)

strcpy(p,obj.p);

len = obj.len;

return *this;

}

void main()

{mainplay();

cout << "successful" << endl;

}

拷貝建構函式的幾個細節

1. 拷貝建構函式裡能呼叫private成員變數嗎?
解答:
這個問題是在網上見的,當時一下子有點暈。其時從名子我們就知道拷貝建構函式其時就是
一個特殊的建構函式,操作的還是自己類的成員變數,所以不受private的限制。

2. 以下函式哪個是拷貝建構函式,為什麼?

  1. X::X(const X&);      
  2. X::X(X);      
  3. X::X(X&, int a=1);      
  4. X::X(X&, int a=1, int b=2);  

解答:對於一個類X, 如果一個建構函式的第一個引數是下列之一:
a) X&
b) const X&
c) volatile X&
d) const volatile X&
且沒有其他引數或其他引數都有預設值,那麼這個函式是拷貝建構函式.

  1. X::X(const X&);  //是拷貝建構函式    
  2. X::X(X&, int=1); //是拷貝建構函式   
  3. X::X(X&, int a=1, int b=2); //當然也是拷貝建構函式

3. 一個類中可以存在多於一個的拷貝建構函式嗎?
解答:
類中可以存在超過一個拷貝建構函式。

  1. class X {   
  2. public:         
  3.   X(const X&);      // const 的拷貝構造
  4.   X(X&);            // 非const的拷貝構造
  5. };  


注意,如果一個類中只存在一個引數為 X& 的拷貝建構函式,那麼就不能使用const X或volatile X的物件實行拷貝初始化.

  1. class X {      
  2. public:  
  3.   X();      
  4.   X(X&);  
  5. };      
  6. const X cx;      
  7. X x = cx;    // error


如果一個類中沒有定義拷貝建構函式,那麼編譯器會自動產生一個預設的拷貝建構函式。
這個預設的引數可能為 X::X(const X&)或 X::X(X&),由編譯器根據上下文決定選擇哪一個。


相關推薦

C++拷貝建構函式拷貝拷貝

拷貝建構函式呼叫時機: 1、物件需要通過另外一個物件進行初始 化:     T t1(10, 20);T t2(0, 0);T t3 = t1; // 拷貝建構函式呼叫的時機一:T t4(t2);  // 拷貝建構函式呼叫的時機 二:2、實參傳遞給形參時呼叫賦值建構函式 拷

C++類的一些細節(過載重寫覆蓋隱藏,建構函式函式拷貝建構函式賦值函式在繼承時的一些問題)

1 函式的過載、重寫(重定義)、函式覆蓋及隱藏 其實函式過載與函式重寫、函式覆蓋和函式隱藏不是一個層面上的概念。前者是同一個類內,或者同一個函式作用域內,同名不同引數列表的函式之間的關係。而後三者是基類和派生類函式不同情況下的關係。 1.1 函式過載

C++的拷貝建構函式operator=運算子過載,拷貝拷貝explicit關鍵字

1、在C++編碼過程中,類的建立十分頻繁。 簡單的功能,當然不用考慮太多,但是從進一步深刻理解C++的內涵,類的結構和用法,編寫更好的程式碼的角度去考慮,我們就需要用到標題所提到的這些內容。 最近,在看單例模式,覺得十分有趣,然而如果想要掌握單例模式,就必須掌握這些內容。下

批註:C++複製建構函式過載賦值操作符總結:預設拷貝,帶指標的需要拷貝

前言 這篇文章將對C++中複製建構函式和過載賦值操作符進行總結,包括以下內容: 複製建構函式和過載賦值操作符的定義;複製建構函式和過載賦值操作符的呼叫時機;複製建構函式和過載賦值操作符的實現要點;複製建構函式的一些細節。 複製建構函式和過載賦值操作符的定義 我們都知道

c++拷貝建構函式賦值運算子=過載拷貝拷貝

 關鍵詞:建構函式,淺拷貝,深拷貝,堆疊(stack),堆heap,賦值運算子 摘要:     在面向物件程式設計中,物件間的相互拷貝和賦值是經常進行的操作。     如果物件在宣告的同時馬上進行的初始化操作,則稱之為拷貝運算。例如:         class1 A(

C++:面試時應該實現的string類(建構函式拷貝建構函式賦值運算子過載和解構函式

一、string類的4個基本函式是什麼? 建構函式 拷貝建構函式 賦值運算子過載 解構函式 二、函式實現 1.建構函式 String(char* pStr = " ")

C++建構函式拷貝構造和解構函式

我們使用內建型別建立物件的時候,因為內建型別是一個固定的型別(比如int),所以編譯器會為我們分配空間(4位元組),使得我們的程式碼正常執行。 而用類例項化出來的物件,因為是自定義型別,所以系統提前並不知道我們所定義出來的型別有多大,佔多少位元組。 在我們用

關於c++預設的建構函式函式拷貝建構函式move函式

在c++中,當我們定義一個類的時候,如果我們什麼都不定義的時候,c++編譯器會預設的為我們生成一些函式。 例如定義一個Example類。 class Example{ }; 當我們定義一個Example類的時候,不定義任何操作的時候,c++編譯系統將為Example類生成如

C++建構函式拷貝建構函式和賦值函式

一.建構函式 1.首先說明一下空類: 對於空類,編譯器會自動加入: 預設建構函式,拷貝建構函式,賦值建構函式,解構函式和取值函式 擴充:空類的大小為1.(因為每個例項在記憶體中都有獨一無二的地址,為了達到這個目的,編譯器往往會給空類增加一個位元組) 2

類的建構函式函式拷貝建構函式賦值函式

 類的四種基本預設函式:建構函式、解構函式、拷貝建構函式、賦值函式。 建構函式:建立類時,系統自動呼叫建構函式,用以初始化,分配空間,沒有自定義的建構函式時,系統預設一個無引數的建構函式。 class book { private:     int isBook;

編寫類String的建構函式拷貝建構函式函式和賦值函式

class String { public: String(const char *str = NULL); // 普通建構函式 String(const String &other); // 拷貝建構函式 ~String(void);

編寫類String 的建構函式拷貝建構函式函式和賦值函式

 編寫類String 的建構函式、解構函式和賦值函式,已知類String 的原型為: class String { public:String(const char *str = NULL); // 普通建構函式String(const String &other

c++的匿名物件的去留問題和拷貝拷貝

匿名物件的去和留問題: 匿名物件的去和留主要取決於你用什麼去接收這個物件, 具體如下: # include <iostream> using namespace std; class

c++建構函式

下面所有的建構函式都將用Student這個類作為例子 class Student { private: static int count;//不屬於任何一個物件 std::string name; char *gender; i

讀書筆記:實現string類的建構函式拷貝建構函式函式過載運算子=

#include <iostream> #include <cassert> #include <cstring> using namespace std; class MyString{ public: MyString(co

拷貝建構函式運算子過載深淺拷貝

#include<iostream> #include<string.h> using namespace std; class Student{ public: Student(){m_strName="Jim";}

預設拷貝建構函式拷貝拷貝

#include using namespace std; class Person { public: Person(char *pN) { cout <<"Constructing "<<pn<<endl; pName=new char (st

編寫String類的普通建構函式拷貝建構函式函式賦值函式

題目:編寫類String的建構函式、解構函式和賦值函式,已知類String的原型為: class String {  public:   String(const char *str = NULL); // 普通建構函式   String(const String

類String的建構函式拷貝建構函式函式和賦值運算子過載函式的實現

#include <iostream> using namespace std; class String { public: String(const char* str= NULL); String(const String& other); ~

String類的建構函式函式拷貝建構函式賦值運算子過載

面試碰到的題,答案來自網路搜尋。 class myString{ private: char* m_data; public: myString(const char *str=NULL); myString(const myString &other)