一 定義 C++ 對象
類提供了對象的藍圖,所以基本上,對象是根據類來創(chuàng)建的。聲明類的對象,就像聲明基本類型的變量一樣。下面的語句聲明了類 Box 的兩個對象:
Box?Box1;??????????//?聲明?Box1,類型為?Box Box?Box2;??????????//?聲明?Box2,類型為?Box
對象 Box1 和 Box2 都有它們各自的數據成員。
二 訪問數據成員
類的對象的公共數據成員可以使用直接成員訪問運算符 (.) 來訪問。為了更好地理解這些概念,讓我們嘗試一下下面的實例:
#includeusing?namespace?std; class?Box { ???public: ??????double?length;???//?長度 ??????double?breadth;??//?寬度 ??????double?height;???//?高度 }; int?main(?) { ???Box?Box1;????????//?聲明?Box1,類型為?Box ???Box?Box2;????????//?聲明?Box2,類型為?Box ???double?volume?=?0.0;?????//?用于存儲體積 ? ???//?box?1?詳述 ???Box1.height?=?5.0;? ???Box1.length?=?6.0;? ???Box1.breadth?=?7.0; ???//?box?2?詳述 ???Box2.height?=?10.0; ???Box2.length?=?12.0; ???Box2.breadth?=?13.0; ???//?box?1?的體積 ???volume?=?Box1.height?*?Box1.length?*?Box1.breadth; ???cout?<<?"Box1?的體積:"?<<?volume?<<endl; ???//?box?2?的體積 ???volume?=?Box2.height?*?Box2.length?*?Box2.breadth; ???cout?<<?"Box2?的體積:"?<<?volume?<<endl; ???return?0; }
當上面的代碼被編譯和執(zhí)行時,它會產生下列結果:
Box1?的體積:210 Box2?的體積:1560
三?定義?C++?對象訪問數據成員
需要注意的是,私有的成員和受保護的成員不能使用直接成員訪問運算符 (.) 來直接訪問。我們將在后續(xù)的教程中學習如何訪問私有成員和受保護的成員。
四 類 & 對象詳解
到目前為止,我們已經對 C++ 的類和對象有了基本的了解。下面的列表中還列出了其他一些 C++ 類和對象相關的概念,可以點擊相應的鏈接進行學習。
類成員函數 類的成員函數是指那些把定義和原型寫在類定義內部的函數,就像類定義中的其他變量一樣。 類訪問修飾符 類成員可以被定義為 public、private 或 protected。默認情況下是定義為 private。 構造函數 & 析構函數 類的構造函數是一種特殊的函數,在創(chuàng)建一個新的對象時調用。類的析構函數也是一種特殊的函數,在刪除所創(chuàng)建的對象時調用。 C++ 拷貝構造函數 拷貝構造函數,是一種特殊的構造函數,它在創(chuàng)建對象時,是使用同一類中之前創(chuàng)建的對象來初始化新創(chuàng)建的對象。 C++ 友元函數 友元函數可以訪問類的 private 和 protected 成員。 C++ 內聯(lián)函數 通過內聯(lián)函數,編譯器試圖在調用函數的地方擴展函數體中的代碼。 C++ 中的 this 指針 每個對象都有一個特殊的指針this,它指向對象本身。 C++ 中指向類的指針 指向類的指針方式如同指向結構的指針。實際上,類可以看成是一個帶有函數的結構。 C++ 類的靜態(tài)成員 類的數據成員和函數成員都可以被聲明為靜態(tài)的。 1、類成員函數
類的成員函數是指那些把定義和原型寫在類定義內部的函數,就像類定義中的其他變量一樣。類成員函數是類的一個成員,它可以操作類的任意對象,可以訪問對象中的所有成員。
讓我們看看之前定義的類 Box,現(xiàn)在我們要使用成員函數來訪問類的成員,而不是直接訪問這些類的成員:
class?Box { ???public: ??????double?length;?????????//?長度 ??????double?breadth;????????//?寬度 ??????double?height;?????????//?高度 ??????double?getVolume(void);//?返回體積 };
成員函數可以定義在類定義內部,或者單獨使用范圍解析運算符 ::來定義。在類定義中定義的成員函數把函數聲明為內聯(lián)的,即便沒有使用 inline 標識符。所以您可以按照如下方式定義Volume()函數:
class?Box { ???public: ??????double?length;??????//?長度 ??????double?breadth;?????//?寬度 ??????double?height;??????//?高度 ??? ??????double?getVolume(void) ??????{ ?????????return?length?*?breadth?*?height; ??????} };
您也可以在類的外部使用范圍解析運算符 ::定義該函數,如下所示:
double?Box::getVolume(void) { ????return?length?*?breadth?*?height; }
在這里,需要強調一點,在 :: 運算符之前必須使用類名。調用成員函數是在對象上使用點運算符(.),這樣它就能操作與該對象相關的數據,如下所示:
Box?myBox;??????????//?創(chuàng)建一個對象 myBox.getVolume();??//?調用該對象的成員函數
讓我們使用上面提到的概念來設置和獲取類中不同的成員的值:
#includeusing?namespace?std; class?Box { ???public: ??????double?length;?????????//?長度 ??????double?breadth;????????//?寬度 ??????double?height;?????????//?高度 ??????//?成員函數聲明 ??????double?getVolume(void); ??????void?setLength(?double?len?); ??????void?setBreadth(?double?bre?); ??????void?setHeight(?double?hei?); }; //?成員函數定義 double?Box::getVolume(void) { ????return?length?*?breadth?*?height; } void?Box::setLength(?double?len?) { ????length?=?len; } void?Box::setBreadth(?double?bre?) { ????breadth?=?bre; } void?Box::setHeight(?double?hei?) { ????height?=?hei; } //?程序的主函數 int?main(?) { ???Box?Box1;????????????????//?聲明?Box1,類型為?Box ???Box?Box2;????????????????//?聲明?Box2,類型為?Box ???double?volume?=?0.0;?????//?用于存儲體積 ? ???//?box?1?詳述 ???Box1.setLength(6.0);? ???Box1.setBreadth(7.0);? ???Box1.setHeight(5.0); ???//?box?2?詳述 ???Box2.setLength(12.0);? ???Box2.setBreadth(13.0);? ???Box2.setHeight(10.0); ???//?box?1?的體積 ???volume?=?Box1.getVolume(); ???cout?<<?"Box1?的體積:"?<<?volume?<<endl; ???//?box?2?的體積 ???volume?=?Box2.getVolume(); ???cout?<<?"Box2?的體積:"?<<?volume?<<endl; ???return?0; }
當上面的代碼被編譯和執(zhí)行時,它會產生下列結果:
Box1?的體積:?210 Box2?的體積:?1560
2、類訪問修飾符
數據隱藏是面向對象編程的一個重要特點,它防止函數直接訪問類類型的內部成員。類成員的訪問限制是通過在類主體內部對各個區(qū)域標記public、private、protected來指定的。關鍵字 public、private、protected 稱為訪問說明符。
一個類可以有多個 public、protected 或 private 標記區(qū)域。每個標記區(qū)域在下一個標記區(qū)域開始之前或者在遇到類主體結束右括號之前都是有效的。成員和類的默認訪問修飾符是 private。
class?Base?{ ? ???public: ? ??//?public?members?go?here ? ???protected: ? ??//?protected?members?go?here ? ???private: ? ??//?private?members?go?here ? };
公有(public)成員
公有成員在程序中類的外部是可訪問的。您可以不使用任何成員函數來設置和獲取公有變量的值,如下所示:
#includeusing?namespace?std; ? class?Line { ???public: ??????double?length; ??????void?setLength(?double?len?); ??????double?getLength(?void?); }; ? //?成員函數定義 double?Line::getLength(void) { ????return?length?; } ? void?Line::setLength(?double?len?) { ????length?=?len; } ? //?程序的主函數 int?main(?) { ???Line?line; ? ???//?設置長度 ???line.setLength(6.0);? ???cout?<<?"Length?of?line?:?"?<<?line.getLength()?<<endl; ? ???//?不使用成員函數設置長度 ???line.length?=?10.0;?//?OK:?因為?length?是公有的 ???cout?<<?"Length?of?line?:?"?<<?line.length?<<endl; ???return?0; }
當上面的代碼被編譯和執(zhí)行時,它會產生下列結果:
Length?of?line?:?6 Length?of?line?:?10
私有(private)成員
私有成員變量或函數在類的外部是不可訪問的,甚至是不可查看的。只有類和友元函數可以訪問私有成員。
默認情況下,類的所有成員都是私有的。例如在下面的類中,width是一個私有成員,這意味著,如果您沒有使用任何訪問修飾符,類的成員將被假定為私有成員:
class?Box { ???double?width; ???public: ??????double?length; ??????void?setWidth(?double?wid?); ??????double?getWidth(?void?); };
實際操作中,我們一般會在私有區(qū)域定義數據,在公有區(qū)域定義相關的函數,以便在類的外部也可以調用這些函數,如下所示:
#includeusing?namespace?std; ? class?Box { ???public: ??????double?length; ??????void?setWidth(?double?wid?); ??????double?getWidth(?void?); ? ???private: ??????double?width; }; ? //?成員函數定義 double?Box::getWidth(void) { ????return?width?; } ? void?Box::setWidth(?double?wid?) { ????width?=?wid; } ? //?程序的主函數 int?main(?) { ???Box?box; ? ???//?不使用成員函數設置長度 ???box.length?=?10.0;?//?OK:?因為?length?是公有的 ???cout?<<?"Length?of?box?:?"?<<?box.length?<<endl; ? ???//?不使用成員函數設置寬度 ???//?box.width?=?10.0;?//?Error:?因為?width?是私有的 ???box.setWidth(10.0);??//?使用成員函數設置寬度 ???cout?<<?"Width?of?box?:?"?<<?box.getWidth()?<<endl; ? ???return?0; }
當上面的代碼被編譯和執(zhí)行時,它會產生下列結果:
Length?of?box?:?10 Width?of?box?:?10
保護(protected)成員
保護成員變量或函數與私有成員十分相似,但有一點不同,保護成員在派生類(即子類)中是可訪問的。
在下一個章節(jié)中,您將學習到派生類和繼承的知識?,F(xiàn)在您可以看到下面的實例中,我們從父類Box派生了一個子類smallBox。
下面的實例與前面的實例類似,在這里width成員可被派生類 smallBox 的任何成員函數訪問。
#includeusing?namespace?std; ? class?Box { ???protected: ??????double?width; }; ? class?SmallBox:Box?//?SmallBox?是派生類 { ???public: ??????void?setSmallWidth(?double?wid?); ??????double?getSmallWidth(?void?); }; ? //?子類的成員函數 double?SmallBox::getSmallWidth(void) { ????return?width?; } ? void?SmallBox::setSmallWidth(?double?wid?) { ????width?=?wid; } ? //?程序的主函數 int?main(?) { ???SmallBox?box; ? ???//?使用成員函數設置寬度 ???box.setSmallWidth(5.0); ???cout?<<?"Width?of?box?:?"<<?box.getSmallWidth()?<<?endl; ? ???return?0; }
當上面的代碼被編譯和執(zhí)行時,它會產生下列結果:
Width?of?box?:?5
3、類構造函數 & 析構函數 類的構造函數
類的構造函數是類的一種特殊的成員函數,它會在每次創(chuàng)建類的新對象時執(zhí)行。
構造函數的名稱與類的名稱是完全相同的,并且不會返回任何類型,也不會返回 void。構造函數可用于為某些成員變量設置初始值。
下面的實例有助于更好地理解構造函數的概念:
#includeusing?namespace?std; ? class?Line { ???public: ??????void?setLength(?double?len?); ??????double?getLength(?void?); ??????Line();??//?這是構造函數 ? ???private: ??????double?length; }; ? //?成員函數定義,包括構造函數 Line::Line(void) { ????cout?<<?"Object?is?being?created"?<<?endl; } ? void?Line::setLength(?double?len?) { ????length?=?len; } ? double?Line::getLength(?void?) { ????return?length; } //?程序的主函數 int?main(?) { ???Line?line; ? ???//?設置長度 ???line.setLength(6.0);? ???cout?<<?"Length?of?line?:?"?<<?line.getLength()?<<endl; ? ???return?0; }
當上面的代碼被編譯和執(zhí)行時,它會產生下列結果:
Object?is?being?created Length?of?line?:?6
帶參數的構造函數
默認的構造函數沒有任何參數,但如果需要,構造函數也可以帶有參數。這樣在創(chuàng)建對象時就會給對象賦初始值,如下面的例子所示:
#includeusing?namespace?std; ? class?Line { ???public: ??????void?setLength(?double?len?); ??????double?getLength(?void?); ??????Line(double?len);??//?這是構造函數 ? ???private: ??????double?length; }; ? //?成員函數定義,包括構造函數 Line::Line(?double?len) { ????cout?<<?"Object?is?being?created,?length?=?"?<<?len?<<?endl; ????length?=?len; } ? void?Line::setLength(?double?len?) { ????length?=?len; } ? double?Line::getLength(?void?) { ????return?length; } //?程序的主函數 int?main(?) { ???Line?line(10.0); ? ???//?獲取默認設置的長度 ???cout?<<?"Length?of?line?:?"?<<?line.getLength()?<<endl; ???//?再次設置長度 ???line.setLength(6.0);? ???cout?<<?"Length?of?line?:?"?<<?line.getLength()?<<endl; ? ???return?0; }
當上面的代碼被編譯和執(zhí)行時,它會產生下列結果:
Object?is?being?created,?length?=?10 Length?of?line?:?10 Length?of?line?:?6
使用初始化列表來初始化字段
使用初始化列表來初始化字段:
Line::Line(?double?len):?length(len) { ????cout?<<?"Object?is?being?created,?length?=?"?<<?len?<<?endl; }
上面的語法等同于如下語法:
Line::Line(?double?len) { ????cout?<<?"Object?is?being?created,?length?=?"?<<?len?<<?endl; ????length?=?len; }
假設有一個類 C,具有多個字段 X、Y、Z 等需要進行初始化,同理地,您可以使用上面的語法,只需要在不同的字段使用逗號進行分隔,如下所示:
C::C(?double?a,?double?b,?double?c):?X(a),?Y(b),?Z(c) { ??.... }
類的析構函數
類的析構函數是類的一種特殊的成員函數,它會在每次刪除所創(chuàng)建的對象時執(zhí)行。
析構函數的名稱與類的名稱是完全相同的,只是在前面加了個波浪號(~)作為前綴,它不會返回任何值,也不能帶有任何參數。析構函數有助于在跳出程序(比如關閉文件、釋放內存等)前釋放資源。
下面的實例有助于更好地理解析構函數的概念:
#includeusing?namespace?std; ? class?Line { ???public: ??????void?setLength(?double?len?); ??????double?getLength(?void?); ??????Line();???//?這是構造函數聲明 ??????~Line();??//?這是析構函數聲明 ? ???private: ??????double?length; }; ? //?成員函數定義,包括構造函數 Line::Line(void) { ????cout?<<?"Object?is?being?created"?<<?endl; } Line::~Line(void) { ????cout?<<?"Object?is?being?deleted"?<<?endl; } ? void?Line::setLength(?double?len?) { ????length?=?len; } ? double?Line::getLength(?void?) { ????return?length; } //?程序的主函數 int?main(?) { ???Line?line; ? ???//?設置長度 ???line.setLength(6.0);? ???cout?<<?"Length?of?line?:?"?<<?line.getLength()?<<endl; ? ???return?0; }
當上面的代碼被編譯和執(zhí)行時,它會產生下列結果:
Object?is?being?created Length?of?line?:?6 Object?is?being?deleted
拷貝構造函數
拷貝構造函數是一種特殊的構造函數,它在創(chuàng)建對象時,是使用同一類中之前創(chuàng)建的對象來初始化新創(chuàng)建的對象??截悩嬙旌瘮低ǔS糜冢?/p>
通過使用另一個同類型的對象來初始化新創(chuàng)建的對象。
復制對象把它作為參數傳遞給函數。
復制對象,并從函數返回這個對象。
如果在類中沒有定義拷貝構造函數,編譯器會自行定義一個。如果類帶有指針變量,并有動態(tài)內存分配,則它必須有一個拷貝構造函數??截悩嬙旌瘮档淖畛R娦问饺缦拢?/p>
classname?(const?classna
概念 | 描述 |
---|