使用istream對象作爲條件時,其效果是檢測流的狀態.如果流是有效的,即流未遇到錯誤,那麼檢測成功,返回true
,如果遇到文件結束符(end of file ),或遇到一個無效輸入時(例如輸入的值不是一個整數),istream對象的狀態會變爲無效.處於無效狀態的istream對象使條件變爲假
windows操作系統中,輸入文件結束符的方法是ctrl+z
,然後回車.UNIX系統中包括mac osx系統,輸入ctrl+D
標準庫頭文件通常不帶後綴,自定義的頭文件根據其中定義的類的名字命名,自定義類首字母大寫,用下劃線連接
C語言中的庫,在C++中都可以導入,格式爲c+原庫名
,如cstdio
類類型的變量如果未指定初值,則按類定義指定的方式進行初始化.定義在函數內部的內置類型變量默認是不初始化的,除非有顯式的初始化語句.全局變量默認初始化.
基本數據類型的尺寸(即所佔的比特數)在不同的機器上有所差別,C++標準規定尺寸的最小值,同時允許編譯器賦予這些類型更大的尺寸.
類型所能表示的值的範圍決定了類型轉換的過程
- 非布爾類型算術值賦給布爾類型時,初始值爲0結果爲false,否則結果爲true
- 布爾值賦給非布爾類型,初始值爲false,結果爲0,否則爲1
- 浮點數賦給整數類型,小數部分記爲0,整數所佔空間超出浮點類型的容量,精度可能丟失,保留低位,高位截去
- 賦給無符號類型一個超出它表示範圍的值時,結果是初始值對無符號類型表示數值總數取模後的餘數.
- 賦給帶符號類型一個超出它表示範圍的值時,結果是未定義的(undefined)
- 有符號<<==>>無符號(均是補碼錶示):對原數據內容不變,解釋方式改變(即第一位是否爲符號位,正負數有不同的解釋方式)
- 長整數<<==>>短整數:短變長,符號擴展,長變短,高位截斷,低位保留
編譯器在每個字符串的結尾處添加一個空字符('\0'),因此字符串字面值的實際長度要比他的內容多1.
nullptr是指針字面值
C++中的每個變量都有其數據類型,數據類型決定變量所佔內存空間的大小和佈局方式,該空間能存儲的值的範圍,以及變量能參與的運算.
在C++語言中,初始化和賦值是兩個完全不同的操作,初始化不是賦值,初始化的含義是創建變量時賦予其一個初始值,賦值的含義是把對象的當前值擦除,而以一個新值來替代.
如果定義變量時沒有指定初值,則變量被默認初始化,此時變量被賦予默認值,默認值到底是什麼由變量類型決定,同時定義變量的位置也會對此有影響.如果是內置類型的變量未被顯式初始化,它的值由定義的位置決定.定義於任何函數體之外的變量被初始化爲0,定義在函數體內部的內置類型變量將不被初始化.一個未被初始化的內置類型變量的值是未定義的,如果試圖拷貝或以其他形式訪問此類值將引發錯誤.每個類各自決定其初始化對象的方式.
爲了支持分離式編譯,C++語言將聲明和定義區分開.聲明(declaration)使得名字爲程序所知,一個文件如果想使用別處定義的名字則必須包含對那個名字的聲明.而定義(definition)負責創建與名字關聯的實體.變量聲明規定了變量的類型和名字,在這一點上定義與之相同,但是除此之外,定義還申請存儲空間,也可能會爲變量賦一個初始值.如果想聲明一個變量而非定義它,就在變量名前添加關鍵字extern,而且不要顯式初始化變量:
extern int i;//聲明i而非定義i
int j;//聲明並定義j
任何包含了顯式初始化的聲明即成爲定義,可以給extern關鍵字標記的變量賦一個初始值,但是這麼做抵消了extern的作用.extern語句如果包含初始值就不再是聲明,而是定義:
extern double pi = 3.1415;//定義
變量能且只能被定義一次,但是可以被多次聲明.
引用爲對象起了另外一個名字,引用類型引用另外一種類型.通過將聲明符寫成&d的形式來定義引用類型.一般在初始化變量時,初始值會被拷貝到新建的對象中,然而定義引用時,程序把引用和它的初始值綁定(bind)在一起,而不是將初始值拷貝給引用.一旦初始化完成,引用將和它的初始值對象一直綁定在一起.因爲無法令引用重新綁定到另外一個對象,因此引用必須初始化.
引用並非對象,他只是一個已經存在的對象所起的另外一個名字.定義了一個引用之後,對其進行的所有操作都是在與之綁定的對象上進行的.引用只能綁定到對象上,而不能與字面值或某個表達式的計算結果綁定在一起
指針本身就是一個對象,允許對指針賦值和拷貝,而且在指針的生命週期內它可以先後指向幾個不同的對象.指針無需在定義時賦初值.和其他內置類型一樣,在塊作用域內定義的指針如果沒有被初始化,也將擁有一個不確定的值.
任何非0指針對應的條件值都是true
void*
是一種特殊的指針類型,可用於存放任意對象的地址.一個void*
指針存放着一個地址,我們對該地址中到底是個什麼類型的對象並不瞭解.利用void*
指針能做的事比較有限,拿它和別的指針比較,作爲函數的輸入或輸出,賦給另外一個void*
指針,不能直接操作void*
指針所指的對象,因爲我們並不知道這個對象到底是什麼類型,也就無法確定能在這個對象上做哪些操作.概括說來,以void*
的視角來看內存空間也就僅僅是內存空間,沒辦法訪問內存空間中所存的對象.
理解複合類型的聲明
//i是一個int型的數,p是一個int型指針,r是一個int型引用(要理解類型修飾符只是聲明符的一部分)
int i = 1024 , *p = &i, &r = i;
//定義多個變量
//p1是指向int的指針,p2是int類型
int* p1,p2;
面對一條比較複雜的指針或者引用的聲明語句時,從右向左閱讀有助於弄清楚它的真實含義.
因爲const對象一經創建後其值就不能再改變,所以const對象必須初始化.
有兩種方法可以用於定義類型別名
typedef double wages; //wages是double的同義詞
typedef wages base,*p; //base是double的同義詞,p是double*的同義詞
using SI = Sales_item; //SI是Sales_item的同義詞
auto
讓編譯器通過初始值來推算變量的類型.顯然auto定義的變量必須有初始值,使用auto也能在一條語句中聲明多個變量,因爲一條聲明語句只能有一個基本數據類型,所以該語句中所有變量的初始基本數據類型都必須一樣.
c++11新標準規定,可以爲結構體的數據成員提供一個類內初始值,創建對象時,類內初始值將用於初始化數據成員,沒有初始值的成員將被默認初始化.
預處理器是在編譯之前執行的一段程序,可以部分的改變我們所寫的程序,如當預處理器看到#include
標記時就會用指定的頭文件的內容代替#include
一個標準的自定義頭文件結構
#ifndef SALES_DATA_H
#define SALES_DATA_H
#include<string>
struct Sales_data{
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
#endif
使用這些功能可以有效地防止重複包含頭文件