C++ 程式設計/結構
結構是一種複合資料型別,它包含不同型別和不同成員。成員可以透過其名稱進行訪問。結構物件的數值是物件中每個成員的數值的元組。結構也可以被看作是面向物件程式設計 (OOP) 中物件正規化的一種簡單實現。Astruct就像一個class 除了預設訪問許可權(類預設訪問許可權為 private,結構預設訪問許可權為 public)。C++ 還保證只包含 C 型別的結構等效於相同的 C 結構,從而允許訪問舊版 C 函式,它可以(但可能不會)也有建構函式(並且必須有它們,如果一個模板類被用在一個struct)中,與類一樣,如果結構沒有使用者宣告的解構函式,編譯器會隱式宣告一個解構函式。結構還將允許 運算子過載.
結構的定義為
struct myStructType /*: inheritances */ {
public:
// declare public members here
protected:
// declare protected members here
private:
// declare private members here
};
可選關鍵字 public:、protected:、private: 宣告以下成員的保護狀態。它們可以以任何順序放置,每個關鍵字可以出現多次。如果沒有給出保護狀態,則成員為 public。(私有或受保護的成員只能被結構的方法或友元訪問;在後面的章節中解釋)。
由於它在 C 中不受支援,因此在 C++ 中使用繼承的結構並不常見,即使它們與類一樣受支援。更具特色的方面是結構可以具有兩種身份:一種是與型別相關的,另一種是與特定物件相關的。公共訪問標籤有時可以忽略,因為結構對成員函式和欄位的預設狀態是公共的。
型別為 myStructType 的物件是使用宣告的
/* struct */ myStructType obj1 /* , obj2, ... */;
在開頭重複關鍵字 struct 是可選的。
可以在結構定義中直接定義物件,而不是使用結構型別的名稱
struct { /*members*/ } obj1 /*, obj2, .. */ ;
- 為什麼要使用結構而不是類?
較舊的程式語言使用了一種類似的型別稱為記錄(例如:COBOL、FORTRAN),它在 C 中作為 struct 關鍵字實現。因此,C++ 使用結構來遵守 C 的傳統(程式碼和程式設計師)。結構更易於程式設計師和編譯器管理。應該使用一個struct對於 POD (PlainOldData) 型別,它們沒有方法,並且所有資料成員都是public. struct可能在預設情況下使用公共繼承(最常見的一種)以及public訪問(如果先列出公共介面,這就是你想要的)是預期效果。使用一個class,你通常需要在兩個地方插入關鍵字 public,但沒有真正的好處。最終這只是一個約定問題,程式設計師應該能夠習慣它。
- 點物件
作為一個簡單的複合結構示例,考慮數學點概念。從某種程度上來說,一個點是兩個數字(座標),我們將其作為一個整體對待。在數學符號中,點通常用括號寫,逗號分隔座標。例如,(0, 0) 表示原點,(x, y) 表示從原點向右 x 個單位,向上 y 個單位的點。
表示點的自然方法是使用兩個雙精度浮點數。結構或struct是將這兩個值組合成複合物件的解決方案之一。
// A struct definition:
struct Point { double x, y; };
這個定義表明這個結構包含兩個成員,名為x和y。這些成員也稱為例項變數,我將在稍後解釋原因。
在結構定義末尾省略分號是一個常見的錯誤。在花括號後面放分號可能看起來很奇怪,但你會習慣的。這種語法是為了讓程式設計師在定義結構時能夠建立結構的例項。
定義了新結構後,就可以建立具有該型別的變數
struct Point blank;
blank.x = 3.0;
blank.y = 4.0;
第一行是傳統的變數宣告:blank 的型別是 Point。接下來的兩行初始化結構的例項變數。這裡使用的“點符號”類似於在物件上呼叫函式的語法,如fruit.length()。當然,一個區別是函式名後面總是跟著一個引數列表,即使它是空的。
像往常一樣,變數 blank 的名稱出現在框外面,它的值出現在框裡面。在這種情況下,該值是一個包含兩個命名例項變數的複合物件。
- 訪問例項變數
可以使用與寫入它們相同的語法來讀取例項變數的值
double x = blank.x;
表示式blank.x表示“轉到名為 blank 的物件,獲取名為 x 的成員的值”。在這種情況下,我們將該值賦給名為x的區域性變數。請注意,名為x的區域性變數與名為x的例項變數之間沒有衝突。點符號的目的是明確地識別你所指的變數。
可以使用點符號作為任何表示式的部分,因此以下內容是合法的。
cout << blank.x << ", " << blank.y << endl;
double distance = sqrt(blank.x * blank.x + blank.y * blank.y);
第一行輸出 3, 4;第二行計算值為 5。
- 對結構的操作
我們在其他型別上使用的大多數運算子,例如數學運算子(+, %等)和比較運算子(==, >等),不適用於結構。實際上,可以為新型別定義這些運算子的含義,但我們在這本書中不會這樣做。
另一方面,賦值運算子對結構有效。它可以用兩種方式使用:初始化結構的例項變數或將一個結構的例項變數複製到另一個結構。初始化看起來像這樣
Point blank = { 3.0, 4.0 };
花括號中的值依次賦給結構的例項變數。因此,在這種情況下,x獲取第一個值,y 獲取第二個值。
不幸的是,這種語法只能用於初始化,而不能用於賦值語句。因此,以下是非法的。
Point blank;
blank = { 3.0, 4.0 }; // WRONG !!
你可能想知道為什麼這個完全合理的語句應該是非法的,而且沒有很好的答案。(但是,請注意,自 1999 年以來,C 中存在類似的語法,並且正在考慮將其可能包含在未來的 C++ 中)。
另一方面,將一個結構賦給另一個結構是合法的。例如
Point p1 = { 3.0, 4.0 };
Point p2 = p1;
cout << p2.x << ", " << p2.y << endl;
該程式的輸出為 3, 4。
- 結構作為函式引數和返回型別
可以編寫接受或返回結構的函式。例如,findCenter 接受一個 Rectangle 作為引數,並返回一個包含 Rectangle 中心座標的 Point
struct Rectangle {
Point corner;
double width, height;
};
Point findCenter (const Rectangle& box)
{
double x = box.corner.x + box.width/2;
double y = box.corner.y + box.height/2;
Point result = {x, y};
return result;
}
要呼叫此函式,必須傳遞一個 Rectangle 作為引數,並將返回值賦給一個 Point 變數
Rectangle mybox = { {10.0, 0.0}, 100, 200 };
Point center = findCenter (mybox);
printPoint (center);
該程式的輸出為 (60, 100)。
請注意,Rectangle 正在透過引用傳遞給函式 findCenter(在 chapter 函式中解釋),因為這比複製整個結構(如果按值傳遞會發生這種情況)更有效。引用宣告為常量,這意味著函式 findCenter 不會修改引數box,尤其是呼叫者的mybox 將保持不變。
- 指標和結構
結構也可以由指標指向並存儲指標。規則與任何基本資料型別相同。指標必須宣告為指向結構的指標。
結構也可以巢狀,因此結構的有效元素也可以是另一個結構。
//of course you have to define the Point struct first!
struct Rectangle {
Point upper_left;
Point upper_right;
Point lower_left;
Point lower_right;
};
this 關鍵字是一個隱式建立的指標,它只能在結構(或聯合或類)的非靜態成員函式中訪問,並指向呼叫成員函式的物件。此指標在靜態成員函式中不可用。這將在介紹聯合時再次重申,在 關於類部分中提供了更深入的分析。