在網絡上經常會有出現”X(X&)”這個術語.這個就是指拷貝構造函數.很多人還是不知道.也難怪在QQ群中要是有人問起這是什麼意思?知道的人通常會以一個”汗”來回答.
X(X&)的意思是:X引用的X.
要是再來一個:X(const X&);呢? 嘿嘿
理解拷貝構造函數需要知道C++的引用基本概念和函數的按值傳遞方式.否則的話你不但很難理解.而且還會很容易混淆.
這筆記說是復習拷貝構造函數.本質上還是說: 引用基本概念和函數的按值傳遞方式
引用基本概念:
引用(&)說是指針.但又不是指針.但它像一個自動讓編譯器進行逆向使用的指針.最經常使用的地方就是:函數的形參和返回值.當然了.也是可以獨立使用的.所以說像指針但又不是.
使用引用的一些規則以及與指針的不同點:
1. 引用被聲明的時候.必須要進行初始化.//這點就與指針不同了.指針可以在任何時候初始化.好的程序風格在聲明指針的時候也進行初始化.以免忘記.
2. 一個引用被指向一個對象的時候,就不能再指向其它的對象.//指針則可以.
3. 必須要與一塊合法的存儲單元關連.也就是說不能有NULL的引用.//指針則可以聲明為NULL
函數的按值傳遞概念
這個..按值最最基礎的概念就是不會改變原來的值.僅知道這個對於理解拷貝構造還是不夠的.還要知道編譯器如何傳遞和返回的.
舉例說明:
int Example_A_Function(int Para_A,int Para_B)
{
int Sum;
Sum=Para_A+Para_B;
return Sum;
}//注意:在C和C++中,函數的參數入棧是從右到左.也就是說Para_B先進,再是Para_A,最後返回地址入棧.
對上面的函數進行匯編:
_Example_A_Function proc near
push bp
mov bp,sp;建立堆棧框架
sub sp,2
mov ax,word ptr [bp+4];取參數Para_A
add ax,word ptr [bp+6];加參數Para_B
mov word ptr [bp-2],ax
mov ax,word ptr [bp-2]
mov sp,bp;釋放堆棧框架
pop bp
ret
_Example_A_Function endp
而棧頂的則如下圖所示:
傳遞的方式就是這樣子咯.那麼如何返回呢?編譯器把得到的結果放在寄存器中.結束的時候就把寄存器中的值取出來給調用者.
以上這些是編譯器的內置的類型.如果是你自己定義的呢?比如一個類,一個結構.是怎麼實現的呢?
拿結構來打比方://嘿嘿.看到了吧.又是結構.^_^
Example_B
{
int stru_Buffer[100];
double stru_A;
long stru_B;
char stru_C;
}Test_A,Test_B;
Example_B Example_B_Function(Example Test_C)
{
…//做一些其它事
return Test_C;
}
main()
{
Test_B=Example_B_Function(Test_A);
}
在main()函數中,首先調用函數Example_B_Function(),整個Test_A的內容被壓棧.但是這時候就會發現此時有附加的動作了:在調用之前Test_B就被壓入棧了.問題就在這兒了.Test_B不是一個參數.怎麼辦?不管它.軟考沒有要求這個.所以我就不多說.有興趣的朋友(也不能說是有興趣,做一名合格的工程師,這也是必須了解的內容.)可以去看看:約束,棧的框架,重入,bit拷貝等等,就知道是如何處理Test_B了.
有了以上的兩上基礎概念,理解拷貝構造函數好辦好多.
拷貝構造函數概念
構造函數是創建一個新的對象,而傳遞給這個函數的參數必須是我們創立的對象的源對象.但是這個對象是不能被傳入的構造函數的.
咋辦?用指針嗎?明顯不行的,因為按照規則構造一個指針來傳遞是沒有任何意義的.根本的原因是我們現在是從對象創建新對象.而此時引用就可以派上用場了.它可以對源對象的引用.
處理這個過程的函數就是拷貝構造函數了.
什麼時候調用呢?
當用一個已經被初始化過了的自定義類類型對象去初始化另一個新構造的對象的時候,拷貝構造函數就會被自動調用.
以下三點都可以自動調用拷貝構造函數:
1. 一個對象以值傳遞的方式傳入函數體
2. 一個對象以值傳遞的方式從函數返回
3. 一個對象需要通過另外一個對象進行初始化
缺省的拷貝構造函數
1. 如果在類中沒有顯式地聲明一個拷貝構造函數,編譯器將會自動生成一個默認的拷貝構造函數,該構造函數完成對象之間的bitcopy(位拷貝).//這裡還有二個術語:淺拷貝和深拷貝.百度搜一下就有了.
2. 當定義更復雜的類型時,如果沒有創建顯示的拷貝構造函數,C++也將自動地為我們創建拷貝構造函數.但是在這時用位拷貝是沒有意義的,它並不能達到我們的目的.
3. 創建類的時候可以使用組合的方法來進行創建.當我們要用到這個類來處理一些事情的時候,你如果加了一個拷貝構造函數.就等於告訴了編譯器我們要自己處理構造函數的創建,而編譯器就不會提供缺省的構造函數,並且除非我們有創建一個顯示的拷貝構造函數.否則將會編譯出錯.
[這些例子在網絡上都有很多,限於篇幅,就不舉了]
是否選擇顯示定義拷貝構造函數?
說實在的話,即時你不定義你也可以寫出功能類來.但是.僅僅准備用傳值的方式傳遞類的對象時候,此時才用到,如果不要這麼做,那麼就不用了.
當你選擇了要用到拷貝構造函數時候有二個地方要看:
1. 防止按值傳遞
有兩種方法:
className(const className&);或把拷貝構造函數聲明為private
2. 改變外部對象的函數
這種做法讀起代碼有點郁悶,但是我們如果要修改一個非const或被聲明為private的外部對象的時候,就比較好了,也比較好理解代碼.
在< Inside the C++ Object Model >一書也有關於拷貝構造函數的一些使用信息:
[Copy Constructor Construction]
There are three program instances in which a class object is initialized with another object of its class. The most obvious instance, of course, is an object's explicit initialization, such as
class X { ... };
X x;
// explicit initialization of one class object with
another
X xx = x;
The other two are when an object is passed as an argument to a function, such as
extern void foo( X x );
void bar()
{
X xx;
// implicit initialization of foo()'s
// first argument with xx
foo( xx );
}
and when a function returns a class object, such as
X
foo_bar()
{
X xx;
// ...;
return xx;
}
Say the class designer explicitly defines a copy constructor (a constructor requiring a single argument of its class type), such as either of the following:
// examples of user defined copy constructors
// may be multi-argument provided each second
// and subsequent argument is provided with a
// default value
X::X( const X& x );
Y::Y( const Y& y, int = 0 );
In this case, that constructor is invoked, under most circumstances, in each program instance where initialization of one class object with another occurs. This may result in the generation of a temporary class object or the actual transformation of program code (or both).
本文出自 “雞蛋仔” 博客,謝絕轉載!