C++ Primer筆記一

第二章

1.當(dāng)一個(gè)表達(dá)式中既有無(wú)符號(hào)數(shù)又有int值時(shí),int值會(huì)轉(zhuǎn)換成無(wú)符號(hào)數(shù)。

    unsigned u = 10;
    int i = -42;
    std::cout << u+i <<std::endl;//如果int占32位,輸出4294967264

2.如果兩個(gè)字符串字面值位置緊鄰且僅由空格,縮進(jìn)和換行符分隔,則它們實(shí)際上是一個(gè)整體。

    std::cout << "a really,really long string literal “
                "that spans two lines " << std:: endl;

3.列表初始化

    int units_sold = 0;
    int units_sold = {0};
    int units_sold{0};
    int units_sold(0);

上面四條語(yǔ)句都可以做到初始化一個(gè)int變量。用花括號(hào)來(lái)初始化變量的方式稱為列表初始化

初始化不是賦值,初始化的含義是創(chuàng)建變量時(shí)賦予其一個(gè)初始值,而賦值的含義是把對(duì)象的當(dāng)前值擦除,而以一個(gè)新值來(lái)替代。

4.默認(rèn)初始化
如果是內(nèi)置類型的變量未被顯式初始化,它的值由定義的位置決定。定義于任何函數(shù)體之外的變量被始化為0.定義在函數(shù)體內(nèi)部的內(nèi)置類型變量將不被初始化。

定義于函數(shù)體內(nèi)的內(nèi)置類型的對(duì)象如果沒(méi)有初始化,則其值未定義。類的對(duì)象如果沒(méi)有顯式地初始化,則其值由類確定。

5.變量聲明與定義
為了支持分離式編譯,C++語(yǔ)言將聲明和定義區(qū)分開(kāi)來(lái)。聲明 讓名字為程序所知,一個(gè)文件如果想使用別處定義的名字則必須包含對(duì)那個(gè)名字的聲明。而定義 負(fù)責(zé)創(chuàng)建與名字關(guān)聯(lián)的實(shí)體。變量聲明規(guī)定了變量的類型和名字,而定義除此之外,還申請(qǐng)存儲(chǔ)空間,也可能會(huì)為變量賦一個(gè)初始值。

    extern int i;   //聲明i而不是定義i
    int j;  //聲明并定義j

6.作用域
作用域能彼此包含,被包含的作用域稱為內(nèi)層作用域,包含著別的作用域的作用域稱為外層作用域。
作用域中一旦聲明了某個(gè)名字,它所嵌套著的所有作用域中都能訪問(wèn)該名字。同時(shí)允許在內(nèi)層作用域中重新定義外層作用域已有的名字。


7.復(fù)合類型

一條聲明語(yǔ)句由一個(gè)基本數(shù)據(jù)類型和緊隨其后一個(gè) 聲明符 列表組成。

  • 引用 為對(duì)象起了另外一個(gè)名字,引用類型引用另外一種類型。通過(guò)將聲明符寫(xiě)成&d的形式來(lái)定義引用類型,其中d是聲明的變量名。
    int ival = 1024;
    int &refVal = ival; //refVal指向ival(是ival的另一個(gè)名字)
    int &refVal2;   //報(bào)錯(cuò):引用必須被初始化。

一般在初始化變量時(shí),初始值會(huì)被拷貝到新建的對(duì)象中。但是在定義引用時(shí),程序把引用和它的初始值 綁定 在一起,而不是將初始值拷貝給引用。因?yàn)闊o(wú)法令引用重新綁定到另外一個(gè)對(duì)象,因此引用必須初始化。引用并非一個(gè)對(duì)象,只是一個(gè)已經(jīng)存在的對(duì)象所起的另外一個(gè)名字。
引用只能綁定在對(duì)象上,而不能與字面值或某個(gè)表達(dá)的計(jì)算結(jié)果綁定在一起。

除了兩種例外情況,其他所有引用的類型都要和與之綁定的對(duì)象嚴(yán)格匹配。

    第一種:在初始化常量引用時(shí)允許用任意表達(dá)式作為初始值,只要該表達(dá)式的結(jié)果能轉(zhuǎn)換成引用的類型即可。
    int i  = 42;
    const int &r1 = i;
    const int &r2 = 42;
    const int &r3 = r1 * 2;
    double dval = 3.14;
    const int &ri = dval;
    int &r4 = r1 * 2; //error
    編譯器在這里把代碼變成 
        const int temp = dval;
        const int &ri = temp;
    即ri綁定了一個(gè)臨時(shí)量對(duì)象。臨時(shí)量對(duì)象就是當(dāng)編譯器需要一個(gè)空間來(lái)暫存表達(dá)式的求值結(jié)果時(shí)臨時(shí)創(chuàng)建的一個(gè)未命名的對(duì)象。(也叫臨時(shí)量)
  • 指針 是”指向“另外一種類型的復(fù)合類型。相比于引用:指針本身就是一個(gè)對(duì)象,允許對(duì)指針賦值和拷貝,而且在指針的生命周期內(nèi)它可以先后指向幾個(gè)不同的對(duì)象;指針無(wú)須在定義時(shí)賦初值。
    空指針的生成方法:
int *p1 = nullptr;
int *p2 = 0;
int *p3 = NULL;     //新標(biāo)準(zhǔn)下最好使用nullptr,避免使用NULL;

除了兩種例外情況,其他所有指針的類型都要和它所指向的對(duì)象嚴(yán)格匹配。

    第一種:允許令一個(gè)指向常量的指針指向一個(gè)非常量對(duì)象 。

void型指針可用于存放任意對(duì)象的地址。不能直接操作void指針?biāo)傅膶?duì)象,因?yàn)椴⒉恢肋@個(gè)對(duì)象到底是什么類型,無(wú)法確定能在這個(gè)對(duì)象上執(zhí)行哪些操作。(可以與其它指針比較,作為函數(shù)的輸入或輸出,或者賦給另外一個(gè)void*指針。)

面對(duì)一條比較復(fù)雜的指針或引用的聲明語(yǔ)句時(shí),從右向左閱讀有助于弄清楚它的真實(shí)含義

8.const限定符
const類型的對(duì)象只能執(zhí)行不改變其內(nèi)容的操作。

如果想在多個(gè)文件之間共享const對(duì)象,必須在變量的定義之前添加extern關(guān)鍵字。

對(duì)const的引用可能引用一個(gè)并非const的對(duì)象。對(duì)const的引用僅對(duì)引用可參與的操作做出了限定,對(duì)于引用的對(duì)象本身是不是一個(gè)常量限定。因此對(duì)象也可能是個(gè)非常量,允許通過(guò)其他途徑改變它的值。

int i = 42;
int &r1 = i;
const int &r2 = i;
r1 = 0;
r2 = 0;     //error
上面代碼雖然不允許通過(guò)r2修改i的值,但是可以通過(guò)r1修改,或者直接給i賦值。

指針和const:類似于對(duì)const的引用,指向常量的指針不能用于改變其所指對(duì)象的值。要存放常量對(duì)象的地址,只能使用指向常量的指針。

const double pi = 3.14;
double *ptr = π //error
const double *cptr = π
*cptr = 42; //error
允許一個(gè)指向常量的指針指向一個(gè)非常量對(duì)象:
    double dval = 3.14;
    cptr = &dval;   //正確,但是不能通過(guò)cptr來(lái)改變dval的值。

常量指針(const pointer):常量指針必須初始化,一旦初始化完成,它的值(即存放的地址)就不能再改變了。

int errNumb = 0;
int *const curErr = &errNumb;   //curErr將一直指向errNumb
const double pi = 3.14159;
const double *const pip = π //pip是一個(gè)指向常量對(duì)象的常量指針。

用名詞 * 頂層const(top-level const) 表示指針本身是個(gè)常量,底層const(low-level const)*表示指針?biāo)傅膶?duì)象是一個(gè)常量。
更一般的,頂層const可以表示任意的對(duì)象是常量,底層const則與指針和引用等復(fù)合類型部分有關(guān)。比較特殊的是指針類型既可以是頂層const也可以是底層const。

int i = 0;
int *const p1 = &i; //不能改變p1的值,頂層const;
const int ci = 42; //不能改變ci的值,頂層const;
const int *p2 = &ci;//允許改變p2的值,這是一個(gè)底層const;
const int *const p3 = p2; //右邊的const是頂層const,左邊的是底層const;
const int &r = ci; //用于聲明引用的const都是底層const;

9.constexpr與常量表達(dá)式
常量表達(dá)式是指值不會(huì)改變并且在編譯過(guò)程就能得到計(jì)算結(jié)果的表達(dá)式。(如字面值)

一個(gè)對(duì)象(或表達(dá)式)是不是常量表達(dá)式由它的數(shù)據(jù)類型和初始值共同決定。

const int max_files = 20;   //max_files是常量表達(dá)式
const int limit = max_files + 1;  //limit是常量表達(dá)式
int staff_size =27; //staff_size不是,因?yàn)閿?shù)據(jù)類型只是一個(gè)普通int而非const int
const int sz = get_size();  //sz的具體值在運(yùn)行時(shí)獲得,幫也不是。

C++11新標(biāo)準(zhǔn)規(guī)定,允許將變量聲明為constexpr類型,以便由編譯器來(lái)驗(yàn)證變量的值是否是一個(gè)常量表達(dá)式。聲明為constexpr的變量一定是一個(gè)常量,而且必須用常量表達(dá)式初始化。
constexpr int sz = size();//只有當(dāng)size是一個(gè)constexpr函數(shù)時(shí),才是一條正確聲明語(yǔ)句。

指針與constexpr:限定符constexpr僅對(duì)指針有效,與指針?biāo)傅膶?duì)象無(wú)關(guān):

const int *p = nullptr;    //p是一個(gè)指向整形常量的指針;
constexpr int *q = nullptr;    //q是一個(gè)指向整數(shù)的常量指針

10.類型別名:

  1. 傳統(tǒng)方法用關(guān)鍵字typedef定義類型別名。typedef double wages;//wages是double的同義詞。
  2. 新標(biāo)準(zhǔn)規(guī)定了一種新方法,使用別名聲明 來(lái)定義類型的別名:
    using SI = Sales_item; //SI是Sales_item的同義詞。
typedef char *pstring;
const pstring cstr = 0;    //cstr是指向char的常量指針
const pstring *ps;     //ps是一個(gè)指針,它的對(duì)象是指向char的常量指針(指針的指針)。
const是對(duì)給定類型的修飾,pstring實(shí)際上是指向char的指針,因此,const pstring 就是指向char的常量指針,而不指向常量字符的指針。

即不能把類型別名替換成它本來(lái)的樣子去理解。

11.auto類型說(shuō)明符
C++11標(biāo)準(zhǔn)引入了auto類型說(shuō)明符,用它就能讓編譯器替我們?nèi)シ治霰磉_(dá)式所屬的類型,編譯器通過(guò)初始值來(lái)推算變量的類型。所以,auto定義的變量必須有初始值

auto也能在一條語(yǔ)句中聲明多個(gè)變量,但一條聲明語(yǔ)句只能有一個(gè)基本數(shù)據(jù)類型,所 所有變量的初始基本數(shù)據(jù)類型都必須一樣
auto sz = 0, pi = 3.14; //error

auto一般會(huì)忽略掉頂層const,同時(shí)底層const會(huì)保留下來(lái),比如當(dāng)初始值是一個(gè)指向常量的指針時(shí):

int i = 0;
const int ci = i,&cr = ci;
auto b = ci;    //b是一個(gè)整數(shù)(ci的頂層const特性被忽略了,即b不是常量)。
auto c = cr;    //c是一個(gè)整數(shù)
auto d = &i;    //d是一個(gè)整形指針
auto e = &ci;   //e是一個(gè)指向整數(shù)常量的指針(對(duì)常量對(duì)象取地址是一種底層const)

12.decltype類型指示符
C++11新標(biāo)準(zhǔn)引入的第二種類型說(shuō)明符,作用是選擇并返回操作數(shù)的數(shù)據(jù)類型。編譯器分析表達(dá)式并得到它的類型,卻不實(shí)際計(jì)算表達(dá)式的值:
delctype(f()) sum = x; //sum的類型就是函數(shù)f的返回類型。
編譯器并不實(shí)際調(diào)用函數(shù)f,而是使用當(dāng)調(diào)用發(fā)生時(shí)f的返回值類型作為sum的類型。
decltype與引用

int i = 42,*p = &i, &r = i;
decltype(r + 0) b;  //正確:加法的結(jié)果是int,因此b是一個(gè)(未初始化的)int
decltype(*p) c; //錯(cuò)誤:c是int&,必須初始化。
即如果表達(dá)式的內(nèi)容是解引用操作,則decltype將得到引用類型。(解引用指針可以得到指針?biāo)傅膶?duì)象,而且還能給這個(gè)對(duì)象賦值。因此,是int&)

decltype的表達(dá)式如果是加上了括號(hào)的變量,結(jié)果將是引用。
decltype((i)) d; //error

13.自定義數(shù)據(jù)類型struct

不要忘了在struct類體后面加分號(hào)!
新標(biāo)準(zhǔn)規(guī)定,可以為數(shù)據(jù)成員提供一個(gè) 類內(nèi)初始值。創(chuàng)建對(duì)象時(shí),初始值將用于初始化數(shù)據(jù)成員,沒(méi)有初始值的成員,將被默認(rèn)初始化。


預(yù)處理器概述

確保頭文件多次包含仍能安全工作的常用技術(shù)是 預(yù)處理器 。從C繼承而來(lái),而C++還會(huì)用到一項(xiàng)預(yù)處理功能是 頭文件保護(hù)符 ,它依賴于預(yù)處理變量,而預(yù)處理變量有兩種狀態(tài):已定義,未定義。
#define 指令把一個(gè)名字設(shè)定為預(yù)處理變量,而#ifdef與#ifndef指令檢查狀態(tài)。當(dāng)檢查結(jié)果為真時(shí),執(zhí)行后續(xù)操作直到遇到#endif指令。

#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

預(yù)處理器無(wú)視C++中關(guān)于作用域的規(guī)則。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容