天天看點

函數重載與複制構造函數

函數重載與複制構造函數

一、函數重載

1.普通函數重載

 用main函數多次重複調用一個相同名字但是不同類型的函數來處理不同類型的資料。

如 void func(int);

     void func(double);

     float func(float);

2.成員函數的重載

  我們可以将函數的重載推廣到類的成員函數。

  class  boy

  {

     public:

      void  sum();

      void  sum(int  x, int  y);

  }

二、函數的預設參數

在定義某個函數時将它的參數也初始化那麼這個或這些參數就是該函數的預設參數又叫預設參數。

聲明一個帶預設值的函數func

void func(int x = 0, int y = 0);

既然全局函數可以有一個或多個預設值那麼類的成員函數自然也是可以擁有一個或多個預設值。

成員函數的預設值如

class  boy

{

public:

  void  set(int = 30, int = 5);

  void  count(bool = false);

}

那麼具有預設參數的函數與重載函數究竟有什麼差別呢

.重載函數使用友善易于了解。預設函數的如不加标注的話很容易被忽略而且容易被有參數的同名函數覆寫。

.具有預設參數的函數重載的是參數的數值而重載函數重載的是參數的類型。

三、重載構造函數

 既然函數都可以被重載那麼構造函數自然也具備這個特性。如

class  rectangle

   public:

rectangle(){cout<<”構造一個長方形a!\n”;}

rectangle(int l,int w){length=l;width=w;cout<<”長方形b的面積為”<<length*width<<endl;}

rectangle(int  l,int  w,int  h){length=l,width=w,height=h;cout<<”長方體c的體積為”<<length*width*height<<endl;}

1.成員變量的初始化

⑴.對成員變量進行初始化有很多方式其一是在構造函數體中進行初始化如

rectangle(int  l,int  w){length=1;width=w;}

rectangle  a(3,4);

對象a在建立的同時調用了構造函數構造函數通過接收參數l和w将3和4傳遞函數體中

然後又分别賦給了私有成員變量length和width完成了對成員函數變量的初始化工作。

⑵.另外還有一種方式就是在構造函數的函數頭進行初始化。

  rectangle():length(3) , width(4){}

在構造函數的右邊有一個冒号然後是變量的名稱和一對小括号小括号中是要初始化的值或表達式如果對多個成員進行初始化那麼要用逗号将他們隔開最後是一對大括号{}大括号中就是函數所要執行的功能。

2.成員變量的初始化與構造函數

建立一個類a它有3個私有成員變量如下

class  a

  public:

      成員函數1

      成員函數2

  private

      成員變量1

      成員變量2

      成員變量3

這樣對每個成員變量的初始化工作清單如下

aa參數成員變量1參數成員變量2參數成員變量3參數{ }

△注釋在建立某類的一個對象時首先調用該類的構造函數初始化該對象然後才對隊象的成員變量進行初始化成員變量的初始化順序與初始化清單無關而是取決于成員變量在類中的說明順序。在上面的class  a中是private後面的說明順序。

3.複制構造函數

複制構造函數可以複制一個對象如

1  a

2  aa&

第1行聲明了一個構造函數第2行則聲明了一個複制構造函數可以看到它有一個屬于類a的引用那麼這個複制構造函數就可以通過該引用來通路它的對象然後複制該對象的成員變量。如

   aa&one

a類的複制構造函數針對類a的對象one以别名的方式進行通路。 由于引用隻能被初始化而不能被指派是以把這個引用說明為常量引用是非常好的主意這樣構造函數就不必改變傳遞進來的對象。

每個類都有一個預設複制構造函數它使用引用來通路指定隊象的記憶體位址然後複制

該對象的成員變量到自己的成員變量中。

4.構造函數和new運算符

5.再談預設構造函數

四析構函數和delete運算符

#include <iostream>

using namespace std;

class a

a(){cout<<"構造函數執行\n";}

~a(){}

};

int main()

a*p=new a;

delete p;

return 0;

五淺拷貝和深拷貝

 在某些狀況下類内成員變量需要動态開辟堆記憶體如果實行位拷貝也就是把對象裡的值完全複制給另一個對象如a=b。這時如果b中有一個成員變量指針已經申請了記憶體那a中的那個成員變量也指向同一塊記憶體。這就出現了問題當b把記憶體釋放了如析構這時a内的指針就是野指針了出現運作錯誤。

  深拷貝和淺拷貝可以簡單了解為如果一個類擁有資源當這個類的對象發生複制過程的時候資源重新配置設定這個過程就是深拷貝反之沒有重新配置設定資源就是淺拷貝。下面舉個深拷貝的例子。

class ca

 public:

  ca(int b,char* cstr)

  {

   a=b;

   str=new char[b];

   strcpy(str,cstr);

  }

  ca(const ca& c)

   a=c.a;

   str=new char[a]; //深拷貝

   if(str!=0)

    strcpy(str,c.str);

  void show()

   cout<<str<<endl;

  ~ca()

   delete str;

 private:

  int a;

  char *str;

 ca a(10,"hello!");

 ca b=a;

 b.show();

 return 0;

深拷貝和淺拷貝的定義可以簡單了解成如果一個類擁有資源(堆或者是其它系統資源)當這個類的對象發生複制過程的時候這個過程就可以叫做深拷貝反之對象存在資源但複制過程并未複制資源的情況視為淺拷貝。

淺拷貝資源後在釋放資源的時候會産生資源歸屬不清的情況導緻程式運作出錯。

        test(test &c_t)是自定義的拷貝構造函數拷貝構造函數的名稱必須與類名稱一緻函數的形式參數是本類型的一個引用變量,且必須是引用。

當用一個已經初始化過了的自定義類類型對象去初始化另一個新構造的對象的時候拷貝構造函數就會被自動調用如果你沒有自定義拷貝構造函數的時候系統将會提供給一個預設的拷貝構造函數來完成這個過程上面代碼的複制核心語句就是通過test(test &c_t)拷貝構造函數内的p1=c_t.p1;語句完成的。

繼續閱讀