C++除了自動提供默認構(gòu)造函數(shù)和析構(gòu)函數(shù),還有一種叫復(fù)制構(gòu)造函數(shù),用于將一個對象復(fù)制到新創(chuàng)建的對象中。它用于初始化過程中,而不是常規(guī)的賦值過程。原型通常如:
Classname ( const Classname & );
新建一個對象并初始化為同類現(xiàn)有對象時,復(fù)制構(gòu)造函數(shù)都會被調(diào)用,如下4種聲明:
StringBad ditto(motto);
StringBad metoo = motto;
StringBad also = StringBad(motto);
StringBad * ps = new StringBad(motto);
由于按值傳遞對象將調(diào)用復(fù)制構(gòu)造函數(shù),應(yīng)該按引用傳遞對象,節(jié)省調(diào)用時間和空間。
默認的復(fù)制構(gòu)造函數(shù)將逐個復(fù)制非靜態(tài)成員(成員復(fù)制也稱為淺復(fù)制),復(fù)制的是成員的值。如果需要用到靜態(tài)成員,需要顯式定義一個復(fù)制構(gòu)造函數(shù)。函數(shù)頭如:
StringBad::StringBad(const StringBad & s)
淺復(fù)制還有一個隱患,當成員包含指針,在調(diào)用了默認復(fù)制構(gòu)造函數(shù)之后,會出現(xiàn)兩個指針指向同一個地址的情況。此時如果用delete釋放內(nèi)存很容易不小心釋放兩次,此時將導(dǎo)致不確定的、可能有害的后果。解決辦法是定義一個顯式復(fù)制構(gòu)造函數(shù),進行深度復(fù)制!生成一個指向數(shù)據(jù)的副本,并將其地址賦給新的指針。
通常還需要看一看默認的賦值運算符。上面4種情況總是會調(diào)用復(fù)制構(gòu)造函數(shù),但使用=時也可能會調(diào)用賦值運算符(與具體實現(xiàn)有關(guān),比如先用復(fù)制構(gòu)造函數(shù)創(chuàng)建一個臨時對象,然后再通過賦值將臨時對象的值復(fù)制到新對象中。
賦值運算符原型:
Classname & Classname::Operator=(const Classname &);
同樣必須用深度復(fù)制解決值傳遞出現(xiàn)的問題。
補充:復(fù)制構(gòu)造函數(shù)與返回對象的關(guān)系
一般而言,如果方法或函數(shù)要返回局部對象,則應(yīng)返回對象,而不是指向?qū)ο蟮囊谩T谶@種情況下,將使用復(fù)制構(gòu)造函數(shù)來生成返回的對象。如果方法或函數(shù)要返回一個沒有公有復(fù)制構(gòu)造函數(shù)的類(如ostream)的對象,則必須返回一個指向這種對象的引用。最后,有些方法和函數(shù)(如重載的賦值運算符)可以返回對象,也可以返回指向?qū)ο蟮囊茫谶@種情況下,應(yīng)首選引用,因為其不會調(diào)用復(fù)制構(gòu)造函數(shù),效率更高。
新聞熱點
疑難解答