最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

C++ Primer 筆記-第19章 特殊工具與技術(shù)

2023-03-19 22:29 作者:Code有毒  | 我要投稿

19.1 控制內(nèi)存分配

19.1.1 重載newdelete

  1. new一個對象分三個步驟:
    (1)new表達(dá)式調(diào)用名為operator new(或者operator new[])的標(biāo)準(zhǔn)庫函數(shù)。該函數(shù)分配一塊足夠大的、原始的、未命名的內(nèi)存空間以便存儲特定類型的對象(或者對象的數(shù)組)。
    (2)編譯器運(yùn)行相應(yīng)的構(gòu)造函數(shù)以構(gòu)造這些對象,并為其傳入初始值。
    (3)對象被分配了空間并構(gòu)造完成,返回一個指向該對象的指針。

  2. delete一個對象分兩個步驟:
    (1)調(diào)用對象的析構(gòu)函數(shù)。
    (2)編譯器調(diào)用名為operator delete(或者operator delete[])的標(biāo)準(zhǔn)庫函數(shù)釋放內(nèi)存空間。

  3. 如果應(yīng)用程序希望控制內(nèi)存分配的過程,則它們需要定義自己的operator new函數(shù)和operator delete函數(shù)。即使在標(biāo)準(zhǔn)庫中已經(jīng)存在這兩個函數(shù)的定義,我們?nèi)耘f可以定義自己的版本。

  4. 當(dāng)自定義了全局的operator new函數(shù)和operator delete函數(shù)后,我們就負(fù)擔(dān)起了控制動態(tài)內(nèi)存分配的職責(zé)。這兩個函數(shù)必須是正確的:因為它們是程序整個處理過程中至關(guān)重要的一部分。

  5. 當(dāng)我們將上述兩個運(yùn)算符函數(shù)定義成類的成員時,它們是隱式靜態(tài)的,也必須是靜態(tài)的。而且它們不能操縱類的任何數(shù)據(jù)成員。

  6. 標(biāo)準(zhǔn)庫函數(shù)operator newoperator delete的名字容易讓人誤解。和其他operator函數(shù)不同(比如operator=),這兩個函數(shù)并沒有重載new表達(dá)式和delete表達(dá)式。實際上,我們根本無法自定義new表達(dá)式或delete表達(dá)式的行為。

  7. 我們提供新的operator new函數(shù)和operator delete函數(shù)的目的在于改變內(nèi)存分配的方式,但是不管怎樣,我們都不能改變new運(yùn)算符和delete運(yùn)算符的基本含義。

void* operator new(size_t size){

? ?if(void* mem = malloc(size))

? ? ? ?return mem;

? ?else

? ? ? ?throw bad_alloc();

}

void operator delete(void* mem) noexcept {

? ?free(mem);

}

19.2 運(yùn)行時類型識別

  1. 運(yùn)行時類型識別(run-time type identification, RTTI)?的功能由兩個運(yùn)算符實現(xiàn):
    (1)type運(yùn)算符,用于返回表達(dá)式的類型。
    (2)dynamic_cast?運(yùn)算符,用于將基類的指針或引用安全地轉(zhuǎn)換成派生類的指針或引用。

  2. 程序員必須清楚地知道轉(zhuǎn)換的目標(biāo)類型并且必須檢查類型轉(zhuǎn)換是否被成功執(zhí)行。

  3. 使用RTTI必須要加倍小心。在可能的情況下,最好定義虛函數(shù)而非直接接管類型管理的重任。

19.2.1?dynamic_cast運(yùn)算符

  1. dynamic_cast運(yùn)算符的使用形式:
    dynamic_cast<type*>(e)
    dynamic_cast<type&>(e)
    dynamic_cast<type&&>(e)

  2. 我們可以對一個空指針執(zhí)行dynamic_cast,結(jié)果是所需類型的空指針。

  3. 當(dāng)引用的類型轉(zhuǎn)換失敗時,程序拋出一個名為std::bad_cast的異常:

void f(const Base& b) {

? ?try {

? ? ? ?const Derived& d = dynamic_cast<const Derived&>(b);

? ?} catch (bad_cast) {

? ? ? ?// 處理類型轉(zhuǎn)換失敗的情況

? ?}

}

19.2.2?typeid?運(yùn)算符

  1. typeid表達(dá)式的形式是typeid(e),其中e可以是任意表達(dá)式或類型的名字。type操作的結(jié)果是一個常量對象的引用,該對象的類型是標(biāo)準(zhǔn)庫類型type_info或?type_info的公有派生類型。

Derived* dp = new Derived;

Base* bp = dp;?// 兩個指針都指向Derived對象;

// 在運(yùn)行時比較兩個對象的類型

if(typeid(*dp) == typeid(*bp)) {

? ?// dp 和 bp 指向同一類型的對象

}

//檢查運(yùn)行時類型是否是某種指定的類型

if(typeid(*bp) == typeid(Derived)) {

? ?// bp實際指向Derived對象

}

// 注意,typeid應(yīng)該作用于對象,因此我們使用*bp而非bp

// 下面的檢查永遠(yuǎn)是失敗的:bp的類型是指向Base的指針

if(typeid(bp) == typeid(Derived)) {?

?? ?// 此處的代碼永遠(yuǎn)不會執(zhí)行

}

  1. 當(dāng)?typeid作用于指針時(而非指針?biāo)傅膶ο螅?,返回的結(jié)果是該指針的靜態(tài)編譯時類型。

  2. 如果p是一個空指針,則typeid(*p)將拋出一個名為bad_typeid的異常。

19.2.4?type_info

  1. 創(chuàng)建type_info對象的唯一途徑是使用typeid運(yùn)算符。

  2. 對于某種給定的類型來說,name的返回值因編譯器而異并且不一定與在程序中使用的名字一致。對于name返回值的唯一要求是,類型不同則返回的字符串必須有所區(qū)別。

  3. 有的編譯器提供了額外的成員函數(shù)以提供程序中所用類型的額外信息。

19.3 枚舉類型

  1. 枚舉類型(enumeration)?使我們可以將一組整型常量組織在一起。和類一樣,每個枚舉類型定義了一種新的類型。枚舉屬于字面值常量類型。

  2. c++包含兩種枚舉:限定作用域和不限定作用域的。

  3. 在限定作用域的枚舉類型中,枚舉成員的名字遵循常規(guī)的作用域準(zhǔn)則,并且在枚舉類型的作用域外是不可訪問的。與之相反,在不限定作用域的枚舉類型中,枚舉成員的作用域與枚舉類型本身的作用域相同。

  4. 枚舉成員是const,因此在初始化枚舉成員時提供的初始值必須是常量表達(dá)式。

  5. 想要初始化enum對象或者為enum對象賦值,必須使用該類型的一個枚舉成員或者該類型的另一個對象。

  6. 即使某個整數(shù)值恰好與枚舉成員的值相等,它也不能作為函數(shù)的enum實參使用。

  7. c++11新標(biāo)準(zhǔn)中,我們可以在enum的名字后加上冒號以及我們想在該enum中使用的類型。

  8. c++11新標(biāo)準(zhǔn)中,我們可以提前聲明enum。enum的前置聲明(無論隱式地還是顯示地)必須指定其成員的大小。

  9. enum的聲明和定義必須匹配,這意味著在該enum的所有聲明和定義中成員的大小必須一致。而且,我們不能在同一個上下文中先聲明一個不限定作用域的enum名字,然后再聲明一個同名的限定作用域的enum。

19.4 類成員指針

  1. 類成員指針(pointer to member)?是指可以指向類的非靜態(tài)成員的指針。

  2. 成員指針的類型囊括了類的類型以及成員的類型。

  3. 當(dāng)初始化一個這樣的指針時,我們令其指向類的某個成員,但是不指定該成員所屬的對象;直到使用成員指針時,才提供成員所屬的對象。

19.4.1 數(shù)據(jù)成員指針

class Screen {

private:

? ?std::string contents;

}

// pdata可以指向一個常量(非常量)Screen對象的String對象

const string Screen::*pdata;

// 初始化一個成員指針(或給它賦值)時,需指定它所指的成員。

pdata = &Screen::contents;

  1. 當(dāng)我們初始化一個成員指針或為成員指針賦值時,該指針并沒有指向任何數(shù)據(jù)。成員指針指定了成員而非該成員所屬的對象,只有當(dāng)解引用成員指針時我們才提供對象的信息。

Screen myscreen, *pScreen = &myScreen;

// .*解引用pdata以獲得myScreen對象的contents成員

auto s = myScreen.*pdata;

// ->*解引用pdata以獲得pScreen所指對象的contents成員

s= pScreen->*pdata;

// 從概念上來說,這些運(yùn)算符執(zhí)行兩個操作:

// 它們首先解引用成員指針以得到所需的成員

// 然后像成員訪問運(yùn)算符一樣,通過對象(.*)或指針(->*)獲取成員

  1. 可以定義一個返回私有成員指針的函數(shù)。

class Screen {

public:

? ?// data()是一個靜態(tài)成員,返回一個成員指針

? ?static const std::string Screen::*data()

? ? ? ?{ return &Screen::contents; }

private:

? ?std::string contents;

}

// 調(diào)用data()

const string Screen::*pdata = Screen::data();?

// 獲取myScreen對象的contents成員

auto s = myScreen.*pdata;

19.4.2 成員函數(shù)指針

class Screen {

public:

? ?char get_cursor() const;

? ?char get(pos ht, pos wd) const;

? ?// ...

}

// 定義成員函數(shù)的指針:

// pmf是一個指針,它可以指向Screen的某個常量成員函數(shù)

// 前提是該函數(shù)不接受任何實參,并且返回一個char

auto pmf = &Screen::get_cursor;

// 也可以先聲明一個指針,令其指向含有兩個形參的get()

char (Screen::*pmf2)(Screen::pos, Screen::pos) const;

pmf2 = &Screen::get;

// 調(diào)用成員函數(shù)指針

Screen myScreen, *pScreen = &myScreen;

char c1 = (pmyScreen->*pmf)();

char c2 = (myScreen.*pmf2)(0, 0);

  1. 因為函數(shù)調(diào)用符優(yōu)先級比較高,所以在聲明指向成員函數(shù)的指針并使用這樣的指針進(jìn)行函數(shù)調(diào)用時,括號必不可少:(C::*p)(parms)(obj.*p)(args)

  2. 通過使用類型別名,可以令含有成員指針的代碼更容易讀寫。

// Action 是函數(shù)指針的別名

using Action =

? ?char (Screen::*)(Screen::pos, Screen::pos) const;

// 讓Action函數(shù)指針指向Screen的get(pos,pos)

Action get = &Screen::get;

// 可以定義一個函數(shù)action

// 將指向成員函數(shù)的指針Action作為action函數(shù)的形參類型

Screen& action(Screen& , Action = &Screen::get);

Screen myScreen;

// 等價的調(diào)用:

action(myScreen); ? ? ? ? ? ? ? // 使用默認(rèn)實參

action(myScreen, get); ? ? ? ? ?// 使用我們定義的函數(shù)指針get

action(myScreen, &Screen::get) ?// 顯示地傳入地址

  1. 對于普通函數(shù)指針和指向成員函數(shù)的指針來說,一個常見的用法是將其存入一個函數(shù)表當(dāng)中。

19.4.3 將成員函數(shù)用作可調(diào)用對象

  1. 因為成員指針不是可調(diào)用對象,所以我們不能直接將一個指向成員函數(shù)的指針傳遞給算法:

vector<string> svec;

// 錯誤,必須使用.*或->*調(diào)用成員指針

auto fp = &string::empty; ? // fp指向string的empty函數(shù)

find_if(svec.begin(), svec.end(), fp);


// 從指向成員函數(shù)的指針獲取可調(diào)用對象的

// 一種方法是使用標(biāo)準(zhǔn)庫模板function:

function<bool (const string&)> fcn = &string::empty;

find_if(svec.begin(), svec.end(), fcn);

// 第二中方法是使用mem_fn

find_if(svec.begin(), svec.end(), mem_fn(&string::empty));

// 第三中辦法是使用bind

find_if(svec.begin(), svec.end(), bind(&string::empty, _1));

19.6?union:一種節(jié)約空間的類

  1. 聯(lián)合(union)?是一種特殊的類。一個union可以有多個數(shù)據(jù)成員,但是在任意時刻只有一個數(shù)據(jù)成員可以有值。

  2. 當(dāng)我們給union的某個成員賦值后,該union的其他成員就變成未定義的狀態(tài)了。

  3. union不能含有引用類型的成員。

  4. 由于union既不能繼承自其他類,也不能作為基類使用,所以在union中不能含有虛函數(shù)。

  5. 匿名union?不能包含受保護(hù)的成員或私有成員,也不能定義成員函數(shù)。

  6. 當(dāng)我們將union的值改為類類型成員對象的值時,必須運(yùn)行該類型的構(gòu)造函數(shù)。反之,當(dāng)我們將類類型成員的值改為一個其他值時,必須運(yùn)行該類型的析構(gòu)函數(shù)。

19.7 局部類

  1. 類可以定義在某個函數(shù)的內(nèi)部,我們稱這樣的類為局部類(local class)。

  2. 局部類定義的類型只在定義它的作用域內(nèi)可見。

  3. 局部類的所有成員(包括函數(shù)在內(nèi))都必須完整定義在類的內(nèi)部。因此,局部類的作用與嵌套類相比相差很遠(yuǎn)。

  4. 局部類只能訪問外層作用域定義的類型名、靜態(tài)變量以及枚舉成員。

  5. 如果局部類定義在某個函數(shù)內(nèi)部,則該函數(shù)的普通局部便不能被該局部類使用。

  6. 可以在局部類的內(nèi)部再嵌套一個類。此時,嵌套類的定義可以出現(xiàn)在局部類之外。不過,嵌套類必須定義在與局部類相同的作用域內(nèi)。

19.8 固有的不可移植的特性

  1. 為了支持低層編程,c++定義了一些固有的**不可移植(nonportable)的特性。

  2. 該特性是指因機(jī)器而異的特性,當(dāng)我們將含有不可移植特性的程序從一臺機(jī)器轉(zhuǎn)移到另一臺機(jī)器上時,通常需要重新編寫該程序。

19.8.1 位域

  1. 類可以將其(非靜態(tài))數(shù)據(jù)成員定義成位域(bit-filed)。

  2. 位域在內(nèi)存中的布局是與機(jī)器相關(guān)的。

  3. 位域類型必須是整型或枚舉類型。

  4. 通常情況下最好將位域設(shè)為無符號類型,存儲在帶符號類型中的位域的行為將因具體實現(xiàn)而定。

typedef unsigned int Bit;

class File {

? ?Bit mode: 2; ? ? ? ?// mode占2位

? ?Bit modified: 1; ? ?// modified占1位

? ?Bit prot_owner: 3; ?// prot_owner占3位

? ?// ...

}

19.8.2?volatile限定符

  1. volatile是一種類型限定符,告訴編譯器變量可能在程序的直接控制之外發(fā)生改變。它起到一種標(biāo)示作用,令編譯器不對代碼進(jìn)行優(yōu)化操作。

19.8.3 鏈接指示:extern "C"

  1. c++使用鏈接指示(linkage directive)?指出任意非c++函數(shù)所用的語言。


C++ Primer 筆記-第19章 特殊工具與技術(shù)的評論 (共 條)

分享到微博請遵守國家法律
日照市| 曲沃县| 裕民县| 吴忠市| 开阳县| 义马市| 黄龙县| 翼城县| 南投县| 陆丰市| 保山市| 卓资县| 龙泉市| 壤塘县| 渭源县| 左云县| 集安市| 福州市| 信丰县| 凌云县| 巧家县| 元谋县| 昌宁县| 东阳市| 内丘县| 育儿| 于田县| 奎屯市| 新平| 安图县| 于田县| 灯塔市| 五峰| 黑龙江省| 扎赉特旗| 佳木斯市| 保德县| 资溪县| 翁牛特旗| 长顺县| 泰安市|