C++ 程式設計
大多數作業系統要求檔案由名稱字尾特定的副檔名來標識。C++ 標準沒有對檔案如何命名或組織強加任何特定的規則。
檔案組織的特定約定既有技術原因,也有組織上的好處,與我們稍後將要探討的程式碼風格約定非常相似。大多數控制檔案的約定源於歷史偏好和實踐,這些偏好和實踐尤其與 C++ 之前出現的低階語言有關。當考慮到 C++ 是基於 C89 ANSI 標準構建的,並且考慮到相容性,大多數實踐都保持不變,除了作業系統對檔案的改進支援以及對檔案資源管理的便利性。
在處理語言標準上的檔名時,一個演變是預設的包含檔案將沒有副檔名。大多數實現仍然提供舊的 C 風格標頭檔案,這些標頭檔案使用 C 的副檔名“.h”來表示 C 標準庫,但是以相同方式結尾的 C++ 特定標頭檔案名現在沒有副檔名(例如,iostream.h 現在是 iostream)。這種對舊 C++ 標頭檔案的更改是與 名稱空間的實現同時進行的,特別是 std 名稱空間。
選擇檔名與命名變數、函式以及通常所有事物的要求相同。名稱是一個識別符號,不僅方便通訊,還方便結構和組織。
大多數關於檔名考慮因素都是常識性的
- 名稱應該共享同一種語言:在這個方面,專案的國際化應該是一個因素。
- 名稱應該具有描述性,並且由相關標頭檔案共享,副檔名將提供必要的區別。
- 名稱將區分大小寫,請記住保持一致性。
- 不要重用標準標頭檔案名
正如你將在後面看到的,C++ 標準定義了 標頭檔案列表。如果在包含原始檔的搜尋路徑中放置了與標準標頭檔案同名的檔案,則行為是未定義的。
副檔名只有一個用途:指示作業系統、IDE 或編譯器檔案中包含什麼內容。就其本身而言,副檔名不能保證內容。
由於 C 語言原始檔通常具有副檔名“.c”和“.h”,因此在最初,C++ 原始檔通常共享相同的副檔名,或者使用不同的變體來明確地指示 C++ 程式碼檔案。今天,大多數 C++ 實現檔案將使用“.cpp”副檔名,而“.h”用於宣告標頭檔案(最後一個副檔名仍然在大多數彙編程式和 C 編譯器中共享)。
還有其他常見的副檔名變體,例如,“.cc”、“.C”、“.cxx”和“.c++”用於“實現”程式碼。對於標頭檔案,使用相同的副檔名變體,但副檔名的第一個字母通常替換為“h”,例如,“.hh”、“.H”、“.hxx”、“.hpp”、“.h++”等等。
標頭檔案將在後面介紹 預處理器部分時詳細討論,其中將介紹 #include 指令和標準標頭檔案,但總的來說,標頭檔案是一種特殊的 原始碼 檔案,透過 預處理器 的 #include 指令包含進來,通常在“.cpp”檔案的開頭使用。
即使使用單個檔案,C++ 程式也可以編譯,但任何複雜的專案都將從拆分為多個原始檔以方便管理和允許程式碼重用中獲益。初學者會認為這是一個額外的複雜因素,其好處不明顯,尤其是由於大多數初次嘗試可能會導致問題。本節將不僅介紹好處和最佳實踐,還將解釋標準化方法將如何避免和減少複雜性。
- 為什麼將程式碼拆分為多個檔案?
簡單的程式將適合單個原始檔或至少兩個檔案,除此之外,程式可以拆分為多個檔案,以便
- 提高組織性和更好的程式碼結構。
- 促進程式碼重用,在同一個專案中以及跨專案進行程式碼重用。
- 方便多個(通常是同時)編輯。
- 提高編譯速度。
- 原始檔型別
有些作者將副檔名為“.cpp”的檔案稱為“原始檔”,將副檔名為“.h”的檔案稱為“標頭檔案”。但是,這兩者都屬於原始碼。作為本書的約定,所有程式碼,無論是包含在“.cpp”副檔名中(程式設計師會將程式碼放在這裡),還是包含在“.h”副檔名中(用於標頭檔案),都將稱為原始碼。任何時候我們談論“.cpp”檔案,我們都會稱之為“實現檔案”,任何時候我們談論標頭檔案,我們都會稱之為“宣告檔案”。你應該檢查編輯器/IDE 或更改配置以適合你和其他將讀取和使用這些檔案的人。
- 宣告與定義
一般來說,宣告為連結器指定識別符號、型別以及語言元素(如變數和函式)的其他方面。它用於向編譯器宣佈元素的存在,編譯器要求在使用之前宣告變數。
定義為在宣告階段預留的記憶體區域分配值。對於函式,定義提供了函式體。雖然變數或函式可以宣告多次,但它通常只定義一次。
目前這一點並不重要,但它是一個特殊的特性,會影響原始碼在檔案中的分配方式以及編譯器子系統如何處理原始碼。在介紹 變數型別後,我們將 更詳細地介紹這一點。
實現檔案包括程式執行的具體細節,即定義。雖然燈的標頭檔案聲明瞭燈可以做什麼,但燈的“.cpp”檔案定義了燈如何執行。
我們將在後面詳細介紹類定義;下面是一個預覽

#include "light.h"
Light::Light () : on(false) {
}
void Light::toggle() {
on = (!on);
}
bool Light::isOn() const {
return on;
}
標頭檔案 通常包含將在程式其餘部分使用的宣告。類的骨架通常在標頭檔案中提供,而相應的實現檔案則提供定義,以實現在該骨架上的內容。標頭檔案不會被編譯,而是透過使用#include提供給程式的其他部分。

一個典型的標頭檔案如下所示
// Inside sample.h
#ifndef SAMPLE_H
#define SAMPLE_H
// Contents of the header file are placed here.
#endif /* SAMPLE_H */
由於標頭檔案包含在其他檔案中,因此如果它們被包含多次,則可能會出現問題。這通常會導致使用“標頭檔案保護”,使用預處理器指令(#ifndef、#define 和 #endif)。#ifndef 檢查 SAMPLE_H 是否已經出現過,如果沒有,則包含標頭檔案並定義 SAMPLE_H。如果 SAMPLE_H 最初被定義,則該檔案已經被包含,不再被包含。

類通常在標頭檔案中宣告。我們將在後面詳細介紹類宣告;這裡是一個預覽
// Inside light.h
#ifndef LIGHT_H
#define LIGHT_H
// A light which may be on or off.
class Light {
private:
bool on;
public:
Light (); // Makes a new light.
void toggle (); // If light is on, turn it off, if off, turn it on
bool isOn(); // Is the light on?
};
#endif /* LIGHT_H - comment indicating which if this goes with */
此標頭檔案“light.h”宣告將存在一個 light 類,並給出 light 的屬性以及它提供的 method。其他程式設計師現在可以透過在其實現檔案中鍵入#include "light.h"來包含此檔案,這使他們能夠使用此新類。請注意,這些程式設計師不包含與該類相關的實際 .cpp 檔案,該檔案包含有關 light 如何實際工作的詳細資訊。我們將在討論實現檔案後回到這個案例研究。
目標檔案是編譯器在原始碼和最終可執行檔案之間作為中間步驟使用的臨時檔案。所有其他不是原始碼或源自原始碼的原始檔,構建(建立)程式所需的支撐資料。這些檔案的副檔名可能因系統而異,因為它們取決於 IDE/編譯器和程式的必要性,它們可能包括圖形檔案或原始資料格式。
編譯器生成原始碼的等效機器程式碼(目的碼),包含二進位制語言(機器語言)指令,供計算機使用以按照原始碼中的指令進行操作,然後可以將其連結到最終程式。此步驟確保程式碼有效,並將順序排列成可執行程式。大多數目標檔案使用副檔名 (.o),具有與上述 (.cpp/.h) 檔案相同的限制。
庫通常以二進位制形式分發,使用 (.lib) 副檔名和提供其使用介面的標頭檔案 (.h)。庫也可以動態連結,在這種情況下,副檔名可能取決於目標作業系統,例如,windows 庫通常使用 (.dll) 副檔名,這將在本書後面關於庫部分中介紹。
原始碼通常附帶一個名為“Makefile”的特定指令碼檔案(沒有標準副檔名或標準直譯器)。這種型別的指令碼檔案不受 C++ 標準的涵蓋,即使它被廣泛使用。
在一些專案中,尤其是當處理大量外部依賴項或特定配置(如支援特殊硬體)時,需要自動化大量不相容的編譯序列。這些指令碼旨在減輕此任務。詳細解釋程式設計師在使用(或不使用)此類系統時可能做出的無數變化和可能的選擇超出了本書的範圍。您應該檢視 IDE、make 工具的文件或您嘗試編譯的原始碼上提供的資訊。
