程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++學習摘要之二:構造函數和析構函數

C++學習摘要之二:構造函數和析構函數

編輯:關於C++

構造函數和析構函數是類的兩個特殊的成員函數

1.構造函數

構造函數(constructor)是類的一個特殊的成員函數,它與類名同名。當定義該類的對象時,構造函數將被系統自動調用用以實現對該對象的初始化。

構造函數不能有返回值,因而不能指定包括void在內的任何返回值類型。

構造函數的定義與其他成員函數的定義一樣可以放在類內或類外。

構造函數的定義格式為:

類名(形參說明)

{函數體}

構造函數既可以定義成有參函數,也可以定義成無參函數,要根據問題的需要來定。

注意:程序中不能直接調用構造函數,構造函數是在創建對象時由系統直接調用的,因此,在構造函數中一般完成初始化類成員變量的操作。

2.構造函數的重載

一個類中出現了兩個以上的同名的成員函數時,稱為類的成員函數的重載。

在類的成員函數的重載中,比較常見形式是構造函數的重載,當類中出現了重載構造函數時,C++語言將根據構造函數中的參數個數和類型選擇合適的構造函數來完成對象的構造。

3.默認構造函數與缺省參數的構造函數

如果在類中沒有顯示定義構造函數,則編譯系統會為該類提供一個默認的構造函數,該默認構造函數是一個無參函數,函數體為空,它僅僅負責創建對象,而不做任何初始化工作(即不給相應的數據成員賦初值),所以在該類的對象創建時不能保證有一個確定的初始狀態。

良好的編程習慣應該是給類提供合適的完成初始化工作的構造函數。

但是,只要一個類定義了一個構造函數(不一定是無參構造函數),編譯系統就不再提供默認的構造函數。

當構造函數具有缺省參數時,稱為具有缺省參數的構造函數,在使用具有缺省參數的構造函數時,要防止二義性。

4.拷貝構造函數

拷貝構造函數是一種特殊的構造函數。定義拷貝構造函數的一般格式為:

類名::類名(const 類名 &形式參數)

{ 函數體 }

拷貝構造函數的函數名與類名同名。該函數也沒有返回值。

拷貝構造函數的功能是通過將一個同類對象的值拷貝給一個新對象,來完成對新對象的初始化,即用一個對象去構造另外一個對象。

如果在類的定義中沒有定義拷貝構造函數,則編譯系統將自動生成一個具有上述形式的默認的拷貝構造函數,作為該類的公有成員。

5.析構函數

與構造函數對應的是析構函數。當一個對象被定義時,系統會自動調用構造函數為該對象分配相應的資源,當對象使用完畢後且在對象消失前,系統會自動調用類的析構函數來釋放這些系統資源。

析構函數也是類的一個特殊的成員函數,其函數名稱是在類名的前面加上“~”;它沒有返回值,也沒有參數。一個類中只能擁有一個析構函數,所以析構函數不能重載。

析構函數的定義方式為:

~類名()

{ 函數體 }

如果程序員在定義類時沒有為類提供析構函數,則系統會自動創建一個默認的析構函數,其形式為:

~類名()

{ }

對象被析構的順序與其創建時的順序正好相反,即最後構造的對象最先被析構。

如果一個對象是被new運算符動態創建的,當使用delete運算符釋放它時,delete將會自動調用析構函數。

6.一個類的對象作為另一個類的數據成員

當一個類中的數據成員是某一個類的對象時,可稱這種成員是新建類的子對象或對象成員,則新類的定義格式可表示為:

calss X
{
   類名1 成員名1;
   類名2 成員名2;
   類名3 成員名3;
    ……………
   類名n 成員名n;
    ….………… //其他成員
};
其中,X為新建類的類名,類名1、類名2、……、類名n必須是已定義過的類。如:
class A {};
class B
{
   A a;
};

則在創建類B的對象(調用類B的構造函數)時,會自動調用類A的構造函數。如果類A的構造函數為有參函數時,通常采用初始化表的方式來調用構造函數。

新類的構造函數的一般定義格式為:

新類(參數表0):成員1(參數表1),成員2(參數表2),…,成員n(參數表n)

{    ……..     }

其中,成員1、成員2、……、成員n是新類中的對象成員;參數表1提供初始化成員1所需的參數,參數表2提供初始化成員2所需的參數,依此類推,並且這幾個參數表中的參數均來自參數表0.另外,初始化新類的非對象成員所需的參數,也由參數表0提供。

7.常對象與常對象成員

(1)常對象

常對象是指對象常量,其定義格式為:

const 類名 對象名;

從格式中可以看出,常對象的定義與一般對象的定義相比,在類名前必須加const關鍵字。

常對象具有以下特點:

l 常對象在定義時必須進行初始化,而且在程序中不能再對其進行更新。

l 通過常對象只能調用類中的常成員函數,而不能調用類中的其他成員函數。

(2)常對象成員

常對象成員分為常成員函數和常數據成員。

1)常成員函數

在類中,使用關鍵字const說明的成員函數成為常成員函數,常成員函數的說明格式為:

類型 函數名(形參表) const;

類中的常成員函數與普通成員函數相比,具有以下特點:

l 常成員函數為類的只讀函數,這種成員函數可以讀取數據成員的值,但不可以更新數據成員的值,它也不能調用該類中沒有const修飾的其他成員函數。

l 常成員函數定義中的const關鍵字是函數類型的一部分,因此在其實現部分中也要帶上const關鍵字。

l 常成員函數定義中的const關鍵字可以參與區分重載函數。

例如:

#include <iostream.h>

class Test_const{
 private:
  int m;
 public:
  Test_const(int arg1) //構造函數
  {
   m=arg1;
  }
  void setvalue(int newvalue);
  void showvalue();
  void showvalue() const; //常成員函數
};

void Test_const::setvalue(int newvalue)
{
 m=newvalue;
}
void Test_const::showvalue()
{
 cout<<"m="<<m<<endl ;
}
void Test_const::showvalue() const //此處的const關鍵字不可少
{
 cout<<"const example m="<<m<<endl ;
}

void main()
{
 Test_const c1(100); //定義對象c1
 const Test_const c2(100); //定義常對象c2
 c1.setvalue(200);
 c1.showvalue(); //此處調用的是函數void showvalue();
 c2.showvalue();    //此處調用的是函數void showvalue() const;
//不能執行語句c2.setvalue(200);因為常對象c2只能調用常成員函數
}

2)常數據成員

類中定義的數據成員,除了可以為一般變量外,還可以為const常量,這種數據成員稱為常數據成員。

構造函數可以對對象的數據成員進行初始化,但如果數據成員為常量成員或引用成員時,則不能在構造函數中直接用賦值語句為其進行賦值。需要利用構造函數所附帶的初始化表進行初始化,即在構造函數的括號後面加上“:”和初始化表,其格式為:

類名::類名(形參表):常數據成員名1(值1),常數據成員名2(值2),……

{
 //構造函數的函數體
}

可以看出,當有多個數據成員時,初始化表中的初始化項有多個,且需要用逗號隔開。

8.類作用域

類作用域又可稱為類域,它是指在類定義中用一對大括號開括起來的范圍。

不同的類的成員函數可以具有相同的名字,因此,需要用作用域運算符“::”來指明該成員函數所屬的類。

在類的成員函數中可以直接引用類的數據成員。但是,如果在成員函數中定義了同名的局部變量時,則必須用作用域運算符“::”來指定,以免混亂。例如:

#include <iostream.h>
class Region{
private:
 int x;
 int y;
public:
 Region(int x,int y)
  {
   Region::x=x;
   Region::y=y;
  }
  void print()
  {
   cout<<"x="<<x<<",y="<<y<<endl ;
 }
};
void main()
{
 Region region(5,10);
 Region *p;
 p=&region;
 region.print();
 p->print();
}

如果要從類外訪問類的成員,則必須通過對象名和圓點成員選擇符“.”或指向對象的指針和箭頭成員選擇符“->”。如上例中的語句region.print()和語句p->print();是等價的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved