天天看點

關于c++中的拷貝構造函數(複制構造函數)

在c++中既存在預設構造函數,又存在預設拷貝構造函數(即複制構造函數,以下均以拷貝構造函數稱呼);

例如以下申明一個Person類

Class CPerson
{
   private :
           int age;
           int height;
           char sex;
  public:
          CPerson (int age,int height,char sex);
          
             
}
CPerson::CPerson(int age,int height,char sex)
{
   age=age;
   height=height;
   sex=sex;
   CPerson * son;
}

   
           

以下執行個體化一個父親的對象

CPerson father1(40,180,'男');//這會他還沒有兒子
//此時如果要再執行個體化一個父親對象father2,并且跟father1一模一樣,這裡就用到了拷貝構造函數。
CPerson father2(father1);
//另一種能達到上面這種拷貝效果的格式
//CPerson father2=father1;

 
           

以上這中拷貝方法的實作實際上是調用了了程式預設的拷貝構造函數

CPerson (const CPerson& p)//加const 是保證不能通過p來改變實參的資料成員

{

   age=p.age;

   height=p.height;

   sex=p.sex;

}

實際上就是利用了father1的引用(引用就是一種特殊的指針);

但是如果這時father1現在有兒子了(孩子他媽是誰并不重要);

father1.son=new CPerson(5,100,‘男’);

這會咱們依然将father1拷貝給father2,這時候就出現拷貝構造函數的兩個重要概念:淺拷貝和深拷貝   ;

1.預設的拷貝構造函數是淺拷貝,形式如下:

 CPerson (const CPerson& p)//加const 是保證不能通過p來改變實參的資料成員

{

age=p.age;

height=p.height;

sex=p.sex;

   son=p.son;//這裡就是淺拷貝,是址傳遞,father1和father2指向同一個兒子的記憶體位址

}

  在淺拷貝中就出現了另一個問題,既然是址傳遞,那麼隻要father1或者father2中任意一個son的資料成員改變,另一個人的son的資料成員同樣改變

2. 深拷貝問題;首先你要明确深拷貝不是程式預設的,哎,你如果自己不寫,那麼就不會有深拷貝;

 具體代碼:

CPerson (const CPerson& p)//加const 是保證不能通過p來改變實參的資料成員

{

age=p.age;

height=p.height;

sex=p.sex;

son=new CPerson(p.son->age,p.son->height,p.son->sex);//這裡就是深拷貝,是值傳遞,father1和father2現在有相同特征的son.但是他們的son是各自的son,自己的son在記憶體上有自己的位址               }    

    關于深拷貝,這裡就出現了不同于淺拷貝的地方;因為深拷貝之後的兩個father有各自自己的son,隻是兩個son長得一模一樣罷了;這時如果你改變任意一個father的son的資料成員,另一個son是不會受到影響的;

注意:淺拷貝一般不要自己寫函數。深拷貝一般就要自己動手了。

另一個用到拷貝構造函數的例子

      函數的參數為對象         CPerson fffffff(CPerson person2);

        這種情況下就又會用到拷貝複制函數;

        首先調用函數時fffffff(person1);

        這是在我們看不見的程式内部到底發生了什麼的?

        首先實參person1将要複制給person2(這時候就調用的拷貝構造函數),你要知道你利用了拷貝構造函數執行個體話一個對象後,在這個對象失效時,又必須調用析構函數,将其清除記憶體;而這個函數傳回一個CPerson類,在你傳回時,你看不見之下程式又一次調用拷貝構造函數,一來一去,兩次拷貝,一次析構;      函數的多次調用對我們程式性能是不好的,會讓程式運作緩慢,那麼解決的辦法的?

       将 CPerson fffffff(CPerson& person2);或者CPerson fffffff(CPerson* person2);

      對應的函數調用形式為 fffffff( person1);和 fffffff(&person1);

   這會咱們就是址傳遞了,管你呢?反正指向的同一個位址,就不存在多次調用拷貝構造函數和析構函數的問題了;

對了,處于一種好的習慣 如果你不打算改變實參的話,那麼就要引用,聲明函數時 CPerson fffffff(const  CPerson& person2)如果你打算改變實參就用指針,CPerson ffffff(CPerson *person2);

以上均為個人學習認識,若有知識點上和書寫上的錯誤,歡迎各位大佬指出;

 介于CSDN新手,,,不會排版,各位大佬見諒。

繼續閱讀