什么是變量?變量或者叫對象,是一個有具名的、可以供程序操作的存儲空間。這里具名是指變量是有名字的,可供操作是指能進行加減乘除或者輸入輸出等操作,存儲空間則是指有一塊屬於它的內存空間。
為了便於說明,標題和后面的內容將對象分為兩種。對於內置的,文章稱作為變量,對於自定義的,稱之為對象。
第一個問題:在C++中,什么是定義,什么是聲明?
①定義:用於為變量分配存儲空間,還可為變量指定初始值。在程序中,變量有且僅有一個定義。
②聲明:用於向程序表明變量的類型和名字。在程序中,變量可以有多個聲明。
定義也是聲明:當定義變量時我們聲明了它的類型和名字。
上面的這些內容很容易理解,很多情況下,定義就是聲明,由於C++支持分離式編譯,因此一個C++程序允許別分成許多塊,由這些塊共同組成完整的程序。既然程序可以分成多塊,那么如果要在所有塊之間共用一個變量,那就要能夠在這些塊之間共享代碼。為了支持這種分離式編譯機制,C++中就將聲明和定義區分開來了。
第二個問題:定義也是聲明,那么如果僅僅聲明?
回答這個問題之前,需要了解什么是作用域,這里假定你已知曉C++的作用域知識。
在需要聲明一個變量之前,先想一想為什么需要聲明變量?因為程序需要使用定義在別處(通常是別的文件中)的變量。這里使用別處的變量暗含了一個意義,這個變量應當是個全局變量,因為當前作用域找不到,所以需要去別的地方找,而別的地方定義的變量應當全局變量,能夠被我看到(這里只考慮全局變量,其他情況暫不考慮)。
既然變量已經在別的地方定義過了,而且變量有且僅有一個定義,那么我不能再次定義而只能聲明了,如何聲明?
聲明的方式是使用extern關鍵詞,形如extern int i,這里有了關鍵詞extern的修飾,因此是一個聲明,而不是定義。從這個聲明中,得知了變量的類型和名字,但是沒有分配內存。
假如給上面聲明的變量一個值,那還是不是聲明呢?回答是:不是。如果這樣extern int i = 10;那么這里的extern關鍵詞就失效了,這句代碼則變成了定義。
從上面兩個問題中,我們可以知道一個頻繁被提及的問題:為什么不能在頭文件中定義全局變量?
因為變量只能被定義一次,包含了頭文件的源文件,都將會定義同樣的全局變量,造成沖突,所以,頭文件中不能定義全局變量。
由此引申的一個問題:定義在一個源文件中的全局變量,如何讓程序所有的其他塊使用?回答是要么每次在每個塊(即源文件)中手動使用extern聲明,要么使用extern關鍵詞僅僅聲明該全局變量,然后將聲明放在一個頭文件中,該頭文件被所有其他快使用。
接下來是類聲明和定義的內容了。
同樣地,什么是類?
現在如果總結出類的特點,估計初學者會覺得很抽象或者難以理解。我們先來說說在C++中如何定義類?
定義類的語法如下:
首先是關鍵詞class或者struct,兩種區別是默認訪問權限。上面我們定義了一個類A_example,定義了一個類A_example也就是定義了一種新的類型A_example,就像int一樣,它是一種類型。
class A_example { public: int i; double d; float f = 10.0f; static char c = 'A'; };
也就是說上面是定義了一種類型,那么這個類里面的int i和double d是定義還是聲明?答案是聲明。
對於其中的float f = 10.0f;是聲明還是定義呢?答案是聲明。雖然這里聲明的同時賦予了值,但它仍然是一個聲明。
對於static char c = 'A';是聲明還是定義?答案還是聲明!如果你認為它是定義,那么你可以試試直接編譯能否通過,編譯器通常會這樣告訴你:
error: non-const static data member must be initialized out of line(大致意思是,你並沒有初始化,你需要在類外進行定義並初始化,因為類里面的只是聲明而已)
從以上我們能很直觀的感受到一個特點:定義一個類時,對於其中的數據成員,不論有無默認值,也不論是static還是非static的,我們只是描述了一個類,注意,僅僅是描述了類,也即,我們只知道它含有哪些類型,如果還定義了函數成員,我們還描述了這種類型的操作。
在A_example的定義中,我們並不知道這個類的具體情況,我們只知道它的屬性,它含有什么類型,但不知道具體相應類型變量的值大小。對於默認值,只是一旦用這個類去實例化一個對象,就像int i那樣,給對象一個默認值而已。
在C語言中則更明顯,為什么使用結構體struct定義一種類型時,不允許對結構體中的變量賦予默認值?原因就是,僅僅定義了類型而已,只是一些聲明而非定義,聲明沒有開辟內存空間,你給它默認值,它沒有地方存儲,因此C語言中結構體是沒有默認值的。
因此,再看下面這段話,相信會有點感覺:
在C++中, 用 "類" 來描述 "對象", 所謂的"對象"是指現實世界中的一切事物。那么類就可以看做是對相似事物的抽象, 找到這些不同事物間的共同點, 如自行車和摩托車, 首先他們都屬於"對象", 並且具有一定得相同點, 和一些不同點, 相同點如他們都有質量、都有兩個輪子, 都是屬於交通工具等。"都有質量"、"兩個輪子"屬於這個對象的屬性, 而"都能夠當做交通工具"屬於該對象具有的行為, 也稱方法。
類是屬於用戶自定義的數據類型, 並且該類型的數據具有一定的行為能力, 也就是類中說描述的方法。通常來說, 一個類的定義包含兩部分的內容, 一是該類的屬性, 另一部分是它所擁有的方法。以 "人類" 這個類來說, 每個人都有自己的姓名、年齡、出生日期、體重等, 為 人類 的屬性部分, 此外, 人能夠吃飯、睡覺、行走、說話等屬於人類所具有的行為。
上面是類的定義,那么類的聲明呢?
類的聲明和普通的內置類型相似,普通的內置類型是聲明變量,即告知變量的類型和名字。對於類聲明,形如class A_example,這里class表明是一種類型,而A_example則是具體的類型名。
從文章最開頭,我們知道:不能在C++的頭文件中放置變量的定義,因為變量只能定義一次,為什么類的定義可以放在頭文件中呢?在類的定義部分我們又得知,類定義只是定義了一種類型,也即說明了一個類,並沒有實際定義類的對象,定義的是類,定義類描述的是新的類型,而描述新類型並不會開辟內存空間去存儲這樣一種新類對象,因此類定義可以存放在頭文件中。