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; }
{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
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. 以下函式哪個是拷貝建構函式,為什麼?
- X::X(const X&);
- X::X(X);
- X::X(X&, int a=1);
- X::X(X&, int a=1, int b=2);
解答:對於一個類X, 如果一個建構函式的第一個引數是下列之一:
a) X&
b) const X&
c) volatile X&
d) const volatile X&
且沒有其他引數或其他引數都有預設值,那麼這個函式是拷貝建構函式.
- X::X(const X&); //是拷貝建構函式
- X::X(X&, int=1); //是拷貝建構函式
- X::X(X&, int a=1, int b=2); //當然也是拷貝建構函式
3. 一個類中可以存在多於一個的拷貝建構函式嗎?
解答:類中可以存在超過一個拷貝建構函式。
- class X {
- public:
- X(const X&); // const 的拷貝構造
- X(X&); // 非const的拷貝構造
- };
注意,如果一個類中只存在一個引數為 X& 的拷貝建構函式,那麼就不能使用const X或volatile X的物件實行拷貝初始化.
- class X {
- public:
- X();
- X(X&);
- };
- const X cx;
- 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)