C++類

C++程式設計允許程式設計師使用類的擴充套件，C中結構體不能包含函式以及過載的運算子。C 結構體與C++ 類的對比.在 C++ 中，結構體 是由關鍵詞 codice_1 定義的一種資料型別。他的成員和基類預設為公有的。這是C++中結構體和類僅有的區別。聚合類.聚合類是一種沒有使用者定義的建構函式，沒有私有非靜態資料成員，沒有基類，沒有虛擬函式。下列的程式碼在 C 和 C++ 具有相同的語法：struct Cint a;double b;struct Dint a;double b;C c;// initialize an object of type C with an initializer-listC c = { 1, 2 };// D has a sub-aggregate of type C. In such cases initializer-clauses can be nestedD d = { 10, 20, { 1, 2 } };POD 結構.一個POD結構。宣告和使用.C++ 的結構體和類具有他們自己的成員。這些成員包括變數，建構函式以及解構函式。成員被宣告成為公共或私有使用說明符codice_6和codice_7來區分。說明符後出現的任何成員會獲得相應的訪問許可權直到下一個說明符的出現。對於繼承的類能夠使用codice_8說明符。基本宣告和成員變數.類和結構體的宣告使用關鍵詞codice_2和codice_1。成員在類和結構體的內部宣告。下面的程式碼段例項了結構體和類的宣告：以上兩個宣告在功能上是等價的。每一段程式碼都定義了一個型別codice_11，其含有兩個成員變數：codice_12和codice_13。注意，大括號後面的分號是必需的。在其中一個宣告之後，codice_11可以被用來定義新的codice_11型別的變數：using namespace std;class personpublic:string name;int age;int main ()person a, b;a.name = "Calvin";b.name = "Hobbes";a.age = 30;b.age = 20;cout « a.name « ": " « a.age « endl;cout « b.name « ": " « b.age « endl;return 0;執行以上程式碼將會輸出Calvin: 30Hobbes: 20成員函式.成員函式是C++ 的類和結構體的一個重要特性。這些資料型別可以包含作為其成員的函式。成員函式分為靜態成員函式與非靜態成員函式。靜態成員函式只能訪問該資料型別的物件的靜態成員。而非靜態成員函式能夠訪問物件的所有成員。在非靜態成員函式的函式體內，關鍵詞codice_16指向了呼叫該函式的物件。這通常是透過thiscall呼叫協議，將物件的地址作為隱含的第一個引數傳遞給成員函式。再次以之前的codice_11型別作為例子：class personstd::string name;int age;public:void print() const;void person::print() constcout « name « ";" « this-&gt;age « endl;/* "name"和"age"是成員變數。"this"關鍵字的值是被呼叫物件的地址。其型別為const person*，原因是該函式被宣告為const。在上面的例子中codice_18函式在類中宣告，並在類的名稱後加上codice_19來限定它後加以定義。codice_12和codice_13是私有的，codice_18被宣告為公有，由於一個被用於類外的成員需要被申明為公有的。透過使用成員函式codice_18，輸出可以被簡化為：a.print();b.print();上述的codice_24和codice_25被稱為呼叫者，當codice_18函式被執行時每一個都引用自己的成員變數。將類或結構的申明放入分開的單元是常見的做法。使用者需要的介面被放入一個頭檔案中而實現則獨立地放入原始碼或者編譯後的形式。非靜態成員函式，可以用const或volatile關鍵詞限定。const限定的成員函式不能修改其他資料成員，也不能呼叫非const限定的其他成員函式。編譯實現時，通常是在const限定的成員函式體內，this所指向的資料成員自動具有const限定，因此是隻讀的。const物件只能呼叫const成員函式；volatile物件只能呼叫volatile限定的成員函式。反之，沒有受到限定的普通物件可以呼叫所有的成員函式，不論它是否為cv限定。建構函式、解構函式不能cv限定。繼承.非POD類的記憶體佈局沒有被C++標準規定。例如，許多流行的C++編譯器透過將父類的欄位和子類的欄位並置來實現單繼承，但是這並不被標準所需求。這種佈局的選擇使得將父類的指標指向子類的操作是平凡的。例如，考慮：class Pint x;class C : public Pint y;一個codice_27的例項和codice_28指向它，在記憶體中可能看起來像這樣：|P::x|↑p一個codice_29的例項和codice_28指向它，在記憶體中可能看起來像這樣：|P::x|C::y|↑p因此，任何操縱codice_27物件的欄位的程式碼都可以操縱在codice_29物件中的codice_27欄位而不需要考慮任何關於codice_29欄位的定義。一個正確書寫的C++程式在任何情況下都不應該對被繼承欄位的佈局有任何假定。使用static_cast或者dynamic_cast型別轉換運算子會確保指標正確的從一個型別轉換為另一個。多重繼承並不那麼簡單。如果一個類codice_35繼承了codice_36和codice_37，那麼兩個父類的欄位需要被按照某種順序儲存，但是。關於多重繼承的更多資訊，參看虛繼承。過載運算子.C++容許程式設計師過載某些運算子，目的是補充庫中未能提供的針對特定類的運算子。同理，很多時自定類也因為內建庫不能提供指定運算子而需要過載。另外，當程式設計師沒有過載或定義某些運算子時，編譯器會自動地建立它們，例如三法則中的複製指定運運算元。依照慣例，過載運算子時應模擬運算子本身意義的功能，例如過載運算子「*」時，程式設計師義務過載為兩數之乘法。另外，宣告一結構如codice_42類，當過載運算子如「*」就要回傳codice_42類：struct integerint i;integer operator*(const integer &amp;k) constreturn integer (i * k.i);};或struct integerint i;integer operator*(const integer &amp;k) const;integer integer::operator*(const integer &amp;k) constreturn integer(i * k.i);在這裡，codice_44關鍵字出現兩次。表示式codice_45中的codice_44關鍵字代表函式不能修改此常數值，而第二個codice_44關鍵字代表此函式不會修改類物件本身。而codice_49之中，符號表示以參照形式呼叫。當呼叫函式時會直接傳遞變數地址，並以變數本身取代這裡的變數codice_51。二元可過載運算子.二元運算子會用函式方式並以「codice_52」識別來進行過載，這裡的引數會是單一引數。實際使用時，二元運算子左方的變數會成為類物件本身，而右方變數則成為傳入引數。integer a = 1;/* 這裡的等號是其中一種二元運算子，我們可利用過載運算子(=)的方式來提供初始化功能，而左方的變數i就是類物件本身，右方的數字1則是傳入引數。 */integer b = 3;/* 變數名字跟類物件內的變數無關 */integer k = a * b;cout « k.i « endl; //輸出3以下是二元可過載運算子列表：運算子可以被用作賦值，意思是原定功能是由右方變數抄寫內部資料到左方變數，但視乎需要也可以被用作其他用途。每個運算子是互相獨立存在，並不依賴其他運算子。例如運算子存在從而運作。一元可過載運算子.一元運算子跟上述的運算子相似，只是一元運算子只會載入類物件本身都是一元前置運算子。以下是一元可過載運算子列表：過載一元運算子時有區分前置和後置式，一元前置運算子按以下格式編寫：codice_60而後置運算子按以下格式編寫：codice_61括號過載.括號運算子有兩種，分別是方形括號運算子。方形括號運算子又名陣列運算子，只能傳入單一引數，而圓形括號運算子卻可以傳入任意數量的引數。方形括號運算子按以下格式過載：codice_64圓形括號運算子按以下格式過載：codice_65注意，引數是指定在第二個括號之中，第一個括號只是運算子符號。建構函式.有時軟體工程師會想要他們的變數在宣告時有一個預設值。這可以透過宣告建構函式做到。person(string N, int A)name = N;age = A;成員變數可以像下面的例子一樣，利用一個冒號，透過一個初始化序列初始化。這與上面不同，它進行了初始化不能被賦值，因而必須透過初始化序列進行初始化。注意花括號不能被省略，即使為裡面為空。預設值可以給予最後的幾個引數類幫助初始化預設值。在上面的例子中，當沒有引數給予建構函式時，等價於呼叫以下的無參建構函式：建構函式的宣告看起來像一個名字和資料型別相同的函式。事實上，我們的確可以用函式呼叫的形式呼叫建構函式。在這種情況下一個codice_11型別的變數會成為返回值：int main()person r = person("Wales", 40);r.print();以上的例子建立了一個臨時的person物件，然後使用複製建構函式將其賦予r。一個更好的建立物件的方式：int main()person r ("Wales", 40);r.print ();具體的程式行為，可以也可以不和變數有關係，可以被作為一部分加入建構函式。person()std::cout « "Hello!" « endl;透過以上的建構函式，當一個codice_11變數沒有被具體的值初始化時，“Hello!”會被列印。預設建構函式.當類沒有定義建構函式時，預設建構函式將被呼叫。class A { int b;};//使用括號建立物件A *a = new A(); //呼叫預設建構函式，b會被初始化為'0'//不使用括號建立物件A *a = new A; //僅分配記憶體，不呼叫預設建構函式，b會有一個未知值然而如果使用者定義了這個類的建構函式，兩個宣告都會呼叫使用者定義的建構函式。而在使用者定義的建構函式中的程式碼會被執行，並且不會賦予b預設值。解構函式.一個解構函式是一個建構函式的逆，當一個類的一個例項被銷燬時會被呼叫，例如當一個類在塊的建構函式執行期間，衍生類別的建構函式還未執行；反之，在基礎類別的解構函式執行期間，衍生類別的解構函式已執行完畢。兩種情況下，都無法使用在衍生類別宣告的變數。類模板.類模板，是對一批僅僅成員資料型別不同的類的抽象，程式設計師只要為這一批類所組成的整個類家族建立一個類模板，給出一套程式程式碼，就可以用來生成多種具體的類，這類可以看作是類模板的例項，從而大大提高程式設計的效率。屬性.C++語法試圖使一個結構的所有方面看起來像一個基本資料型別。因此，運算子過載允許結構像整數和浮點數一樣操作，結構的陣列可以透過方括號宣告，而且指向結構的指標可以透過和指向內建型別的指標通用的方法解引用。記憶體消耗.結構的記憶體消耗至少是組成變數的記憶體大小的總和。參考如下codice_69 結構例子。struct twonumsint a;int b;這個結構包含兩個整型。在當前許多 C++ 編譯器中，整型預設是32 位整型， 所以每個成員變數消耗 4 個位元組的記憶體．因而整個結構至少消耗 8 個位元組的記憶體，見下圖。| a | b |然而，編譯器可能在變數或者結構的結尾新增空的位， 這樣可以保證和給定的計算機結構匹配，通常是把變數新增到 32 位。如下例子所示的結構:struct bytes_and_suchchar c;char C;short int s;int i;double d;可看成|c|C|XX|s | i | d |在記憶體中, XX 表示兩個未被使用的空位元。因為結構可能會使用指標和陣列去宣告 或者初始化變數，結構的記憶體消耗不一定是固定的。另外一個記憶體消耗不固定的例子是模板結構。位欄位.位欄位可以被用來定義比內建型別還要小的類成員變數。透過這個欄位定義的變數，只可以像使用內建的整數型別(例如int, char, short, long...)那樣子使用。struct Aunsigned a:2; // 可以儲存0-3的數字，佔據一個int前2 bit的空間.unsigned b:3; // 可以儲存0-7的數字，佔據之後3 bit的空間.unsigned :0; // 移動到下一個內建型別的末尾unsigned c:2;unsigned :4; // 在c和d中間加4bit的空白unsigned d:1;unsigned e:3;// 記憶體結構/* 4 byte int 4 byte int[1][2][3][4] [5][6][7][8][1] [2] [3] [4][a][a][b][b][b][][][] [][][][][][][][] [][][][][][][][] [][][][][][][][][5] [6] [7] [8][c][c][][][][][d][e] [e][e][][][][][][] [][][][][][][][] [][][][][][][][]位欄位不能在結構體中使用，它只能在使用struct或者class關鍵字定義的類中使用。"this"關鍵字.complex&amp; operator+=(const complex &amp; c)realPart += c.realPart;imagPart += c.imagPart;return *this;