日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++直接初始化和复制初始化

發布時間:2024/3/13 c/c++ 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++直接初始化和复制初始化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

(1)復制初始化的基本原理
我們知道,對象在內存中的直接表象是在內存中占有一個一定大小的空間。分配空間是建立對象的第一步。但是剛剛分配的空間就像一個沒有開墾的荒田,或者是前面對象占有之后留下來的殘余,從理論上講,由于不管是什么大家都是0101,所以就算沒有初始化也是有值的,只是這個值你是不能正確使用的。所以建立對象的關鍵在于如何對該對象所占有的空間進行正確的初始化。

初始化雖然與賦值的結果很像,但是其所面臨的狀態和發生的時間是不同的。從他們的功能來講,初始化與給某個變量賦值的唯一特點就是他是第一次初始化。當然當你認識到這點的時候,他們的區別也就是無所謂了。關鍵在于,初始化,是一個必須的賦值過程,因為如果你不做這方面的動作,你的對像是一個沒有用的(或者不能正常使用的)

直接初始化,就是使用構造函數,定義在申請了對象空間之后如何對各個子空間進行初始賦值,稱他們為直接初始化是很貼切的,應為他就是最為普通的初始化,是構建一個完整對象的一個過程——先將空間申請好,然后給各個子空間(數據屬性)進行相應的賦值。

復制初始化,特點特別之處在于“復制”二字,核心意義就是,我通過對一個已有對象的完全復制,來構建對象。它的過程可以理解成這樣——先申請空間,然后將被復制的對象(空間一樣大)的所有內容全部復制過去,就形成了這個對象。所以,要明確,兩種初始化的方式,都是一構造函數的形式存在的。區別在于他們的參數方面,復制初始化,表達的就是對一個已有同類型的對象進行復制,那么這種構造函數就應該使用某個對象來進行復制,同時因為,C++參數的傳遞默認都是值傳遞,要聲明使用引用的方式(要不然就又復制了一次了);并且是const類型的。


也就是說任何復制初始化的表面特征就是使用“=”號來表達,左邊是對該對象的空間的申明,右邊是另外一個同類型的對象,注意,一定是同類型的對象(即使不是,也會使用類型轉換構造函數來進行構造(前面說過)!形如:

classname objectname=objectname2; //復制初始化。 classname objectname(,,,,,); //直接初始化,有參數。 classname objectname; //直接初始化,沒有參數。 classname *objectpointorname=new classname(,,);

這里的操作有兩個過程,先使用對象構造函數通過直接初始化構造出一個對象,然后將指針放回,不管有沒有參數。

classname objectname=other_objectname3;

這里表達的是,這個othe_objectname3,不是classname這個類型。這個個就要知道,右邊的會通過調用直接初始化構造函數,構造出對應的對象,然后調用復制初始化構造函數。



所以:?構造函數應該分為:1)直接初始化構造函數

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2)復制初始化構造函數

還是要說,復制初始化構造函數看起來像賦值,但是,其實只是像而已,它其實是借用了這種表象,來觸發調用了那個使用同類型對象引用作為參數的復制構造函數。

string null_book="9-999-9999-9"; //先調用了隱式轉換的直接初始化構造函數,然后調用了復制初始化構造函數。string dots(10, '.');//直接調用直接初始化構造函數。string empty_copy=string(); //先調用顯示直接初始化構造函數,然后調用復制初始化構造函數。string empty_direct; //直接調用沒有參數的(默認)構造函數ifstream file1("filename"); //直接初始化ifstream file2="filename"; //雖然語法沒有錯,但是,由于文件對象不能復制,所以不能使用復制初始化,這種做法在文件領域中通常是錯誤的。Sales_item item=string("9-999-99999-9"); //這個語法對與錯,關鍵是看Saltes_item有沒有隱式(沒有使用explicity標志)轉換以string類型為參數的構造函數。


(2)構造函數(用于直接或復制初始化?)的使用模式。

事實上,我們說這些東西特殊,關鍵是他們時候的時候特殊,兩種構造函數(對應兩種初始化方式)都有顯示和隱式的構造方法。

對于直接初始化,我們知道顯示的方法,就是使用類名加上參數(其實就是在調用構造函數),隱式的方法,就是在一個需要該類對象的地方出現了其他的數據類型,于是系統會自動調用對應函數(這個應該在編譯的時候應該調用了)因為這個時候可以檢測出錯誤來。

對于復制初始化,最顯示的調用手段就是使用“=”符號(這個時候應該成為復制初始化符號)。那么還有許多地方是隱式的調用。如參數傳遞時,函數返回時,初始化容器時!

1)對于參數傳遞:我們知道除非是引用參數,否則就是一個使用上層對象復制初始化函數參數的過程。

2)對于函數返回值:我們知道除非是引用返回,否則在return的那個語句就是使用函數內的對象,復制初始化一個上層對象(通常是臨時的,然后馬上有被用于)

3)在某些容器初始化的過程中如:
? vect<string> svec(5);

???這里的過程就是,先使用string默認構造出一個實例對象,然后使用這個對象,復制初始化其它的元素。這個過程是容器的實現細節,其實從外面看,可以理解為直接初始化。
4)數組初始化,有時候使用這樣的語法:

Sales_item primer_eds[]={ string("1231231"),string("3123123")}

?可知這個過程,就是一個先調用直接初始化生成string,然后繼續隱式調用直接初始化生成Sales_item。最后使用復制初始化,給那個數組的各個元素初始化。

從上面兩個關于容器(包括數組)的初始化過程可以看出,他們與普通的類(也是包含許多的元素對象)的不同了?!

(3)組裝復制構造函數。

對,我們現在學習了,默認構造函數(沒有參數的,可能是系統定義,可能是用戶定義,系統只有在沒有任何構造函數的情況下定義默認構造函數),而系統定義的默認構造函數就叫做組裝默認構造函數,還有一種特殊的構造函數——類型轉換構造函數(其實并不特殊);現在學習了組裝復制構造函數(只要用戶沒有主動構造一個復制構造函數(使用類型引用做參數),系統就會自行組裝);就算只定義了復制構造函數,系統也不會自動組裝默認構造函數,所以,如果你定義了復制構造函數,那么一定要定義普通構造函數(最好有默認構造函數)。要不然,就沒有構造函數了。

想到這里,我們發現不管什么什么類型的構造函數,功能都是實例并初始化對象,可能復制構造函數與普通構造函數的過程有些不同(其實就是使用的方法和領域不同),但是他們仍然是平等的。所以只有一個默認構造函數,并且只有當沒有任何自定一構造函數的時候,系統才會有組裝構造函數;而復制構造函數,是一定有的(不管在什么情況)。

其實復制構造函數的本質依然是構造函數,它的功能就是使用那個已知的對象中的元素,“逐個”的賦值給那個需要初始化的對象。所以,你可以把組裝復制構造函數,想象成一個帶有所有對象元素(順序也一至)的初始化列表的構造函數。

與普通構造函數一樣,涉及到對某個元素的初始化時,對于內建類型,直接使用copy的方法,對于類類型,使用定義復制構建函數。如果沒有定義復制構建函數,就使用組裝的,畢竟復制構建函數的參數是一定的,所以基本不存在無法復制的元素的可能。?但是直接構造函數就有可能出現,子元素沒有默認構造函數的情況,而不能進行構造,并且直接構造的時內建類型也有可能不初始化(依編譯器而定)。

另外一個要注意的是,雖然我們沒有辦法進行復制初始化數組(這就是為什么數組沒有辦法作為參數傳遞,或則作為返回值返回,或者定義的時候用一個數組來復制初始化另外一個數組),但是當數組在某個其他類型的里面的是后,這個時候如果發生了復制初始化,作為元素的數組會也被復制初始化,但是,是通過逐個復制元素的方法。
(4)自定義復制構造函數

class Foo{ public:Foo(); //默認構造函數Foo(const Foo&); //復制構造函數 }

其中,const可以不寫(但通常建議這么做),由于復制的作用要用到傳遞參數、返回值,這些都是隱式的調用,所以一定不能將其聲明為explicit。所以可以知道explicit的作用就是承認在可能的情況下,系統默認在需要使用該函數的情況下,能不能自動使用。

從前面我們說可以將組裝復制構造函數用相應的帶有完全初始化列表的構造函數來代替,我們可以發現,復制構造函數要實現的功能基本穩定,所以通常組裝復制構造函數基本可以滿足要求。

所以我們經常不怎么自己定義復制構造函數,但是有些時候程序實現要求我們必須自定義構造函數,這個時候我們就表明了,構建復制構造函數的困難之處,不在于語法?,它與普通的構造函數是一樣的;關鍵是在,構建這個東西的用途,當用途明確后,其他就簡單了。

有些時候,例如
1)對象成員是一個指向某個資源的指針(用戶本意不想只是復制指針,那表明沒有復制指針指向的對象),
2)或者該類型規定每新建一個對象需要做一些動作,那么這個時候就需要自定義復制構造函數
(注意哦!與普通構造函數一樣,構造函數理論上的功能包括空間分配、元素初始化,以及相關處理,那個復制初始化符號“=”左右應該看成一個整體。)
3)或者該類型的每個對象都富有一個唯一ID成員的機制

(5)如何阻止類的復制初始化功能

1)我們知道,我們使用explicity可以聲明,該復制構造函數不能被隱式使用,于是在參數、返回值的那些地方都不能用,但是如何讓普通的復制初始化也不用呢??那就是聲明為private。我們說過。構造函數的特殊還在于,它是直接被外層使用的,不需要套一個什么類的帽子(因為它就是類名),所以如果申明為private那么就不能使用了,這就是為什么大部分的構造函數都被申明為public了。

?

總結

以上是生活随笔為你收集整理的C++直接初始化和复制初始化的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。