C++八股大雜燴

开宝特攻發表於2024-06-16

C++

1 語法&特性

返回值-NRV

有一條語句,A a = f();其中 f()是一個函式,函式里邊申請了一個 A 的物件 b,然後把物件 b 返回。在物件返回的時候,一般情況下要呼叫複製函式,把函式 f()裡邊的區域性物件 b 複製到函式外部的物件 a。但

NRV具名返回值最佳化(Named Return Value)簡單的說就是,如果用了 NRV 最佳化,那就不必要呼叫複製建構函式,編譯器可以這樣做,把 a 的地址傳遞進函式 f(),然後不讓 f()申請要返回的物件 b 的空間,用 a 的地址來代替 b 的地址,這樣當要返回物件 b 的時候,就不必要複製了,因為 b 就是 a,省去了區域性變數 b,省去了複製的過程。

指標傳參

​ 指標作為引數傳遞,也是傳值,即複製一份指標。這同樣意味著你在函式中對指標的操作,並不會真正改變原指標。這裡要注意理解:不改變的,是指標指向哪裡,但是你卻可以透過這個指標,真實的改變原來指標指向的內容。

​ 如果你想修改一個值,你可以傳遞指向它的指標(或引用)。因此如果你想修改指標的值(即指標的指向),那麼你就要傳遞指向指標的指標(或指標的引用)。

​ 但是要注意,如果你修改了指標的指向,那麼原來指標的指向也會變,這就意味著,原來指標指向的那一塊記憶體區域可能無法引用了,那就會造成記憶體洩漏。

(1) 語法
  • 一些“關鍵字”:inline(外部函式變為內聯)、const(不修改)、default()、explict(不隱式型別轉換)、virtual(虛擬函式、虛繼承)、static(類成員/靜態成員)、using(可以在基類中隱藏父類的 public 繼承來的東西)
  • 初始化列表:建構函式後以:開始,進行初始化。
    1. 靜態成員只能在類內定義,類外初始化,不能出現在初始化列表中(因為一個類只含有一份?)
    2. 基類的建構函式,也在初始化列表中呼叫D(int a, int b, int c) : B(a, b), _c(c)(如果基類沒有預設建構函式,那子類必須顯示呼叫)
    3. 初始化順序只看宣告順序(以及建構函式呼叫順序),與初始化列表出現順序無關。(注意區別,跟出現次序有關的是多繼承時,建構函式的呼叫順序)
    4. 子類只關心父類的初始化,不管再往上幾輩的事,爺爺類自有父類負責(虛基類除外:子類還要呼叫虛基類的建構函式來初始化虛基類子物件,每個低層次的類都要寫,但是實際上只有最派生類執行)【最派生類】:建立物件時所指定的類
  • 構造與解構函式
    1. 建構函式呼叫順序:虛基類 \(\Rarr\) 父類(按宣告左到右) \(\Rarr\)客人(類型別資料,按定義前到後)\(\Rarr\) 自己。析構順序與之相反
    2. 不管顯示還是隱式,基類總是要呼叫父類的建構函式,以及解構函式的。因此可以用子類的指標來析構父類,但父類的指標不會析構子類
  • 型別適應:當且僅當
  • 繼承不會繼承基類的構造和解構函式;
  • 虛繼承:虛繼承即讓某個類做出宣告,承諾願意共享它的基類。其中,這個被共享的基類就稱為虛基類。目的是解決菱形繼承問題\(\Rarr\)同名虛基類,在物件中只會產生一份虛基類子物件(全部父類加上子類,共享一個虛基類子物件)
(2) 記憶體佈局
  • 成員函式在程式碼區,不佔有物件的記憶體。成員函式中定義的區域性變數是“共享的”
  • 有虛擬函式的,物件首塊記憶體會存放一個指向虛表的指標。可以(void **)(*(void**)&obj)
  • 有繼承的,子類中先出現的是父類中的資料成員(基類子物件),然後緊跟著是自己的資料成員
  • 如果父類中有虛擬函式,子類也會有一個虛表,如果沒有重寫父類的虛擬函式,那虛表中專案就指向父類的虛擬函式,如果重寫了,那就指向子類的虛擬函式
(3) 常見問題
  1. 複製建構函式引數:
  2. 深淺複製:
  3. 虛建構函式與虛解構函式:

關鍵字和上下文關鍵字

// delete
void func(int)=delete;
// override, final
void f() override final;

類别範本與友元函式

參考這裡

// 模板類中宣告友元函式共有四種:
template <typename T>
class A{
public:
	friend void f1();			// 1.不需要模板引數的,非模板函式
	friend void f2(A<T>& a);	// 2.需要模板引數的,非模板函式
	friend void f3<T>(A<T>& a);	// 3.需要模板引數的,模板函式
	template <typename U>		// 4.需要模板引數且自帶引數的模板函式
	friend void f4(A<U>& a);
private:
	T v;
};

不要在類內宣告的是第二種,在類外定義的卻是第三種了。

智慧指標

Lambda 表示式

auto foo = [capture](parameters)->return_type {func_body}

  • [capture] 用來捕獲表示式外部的變數:

    1. [ = ] :以值(複製)的方式捕獲所有外部變數,函式體內可以訪問,但是不能修改。

    2. [ & ] :以引用的方式捕獲所有外部變數,函式體內可以訪問並修改(需要當心無效的引用);

    3. [ var ] :以值(複製)的方式捕獲某個外部變數,函式體可以訪問但不能修改。

    4. [ &var ] :以引用的方式獲取某個外部變數,函式體可以訪問並修改

    5. [ this ] :捕獲 this 指標,可以訪問類的成員變數和函式

    6. [ =,&var ] :引用捕獲變數 var,其他外部變數使用值捕獲。

    7. [ &,var ] :只捕獲變數 var,其他外部變數使用引用捕獲。

  • (parameters):即自定義函式里面的引數,只能在表示式的封閉範圍內用

  • 返回值可以自動推斷

2 庫與函式速查

getline()

  1. 有兩個 getline()函式,一個在<istream>裡面,透過(輸入流)成員呼叫的方式指出輸入流,一個在<string>裡面,為頂層函式,在引數列表中指出輸入流

  2. getline()實際讀取的為(n - 1)個字元,且會把終止符從流中刪除

  3. 讀到檔案尾返回eofbit

// # include<istream> // 注意是char*,同時要指出讀入的size
istream& getline (char* s, streamsize n, char delim );
// # include<string>
istream& getline (istream&  is, string& str, char delim);

get()

  1. 與 getline()區別在於,讀到 delim 字元後,會中止並將其保留在流中,這就會被下一個使用者讀到

  2. 只有<istream>版本

// 依次為:single character (1),c-string (2),stream buffer (3)
int get(); istream& get (char& c);
istream& get (char* s, streamsize n, char delim);
istream& get (streambuf& sb, char delim);

正規表示式

<regex>庫是 C11 中新增的特性,下面給出一些使用的例子

regex:定義一個正規表示式類,如regex rx("^[0-9]");

match_result

3 標準庫 STL

黑馬STL 底層資料結構總結

陣列

(1) vector

🌟vector 小指南(附帶一些新手錯誤)

  • vector 的大小。裡面似乎存放的只是幾個指標而已,start、fin 等。在使用umap時候發現的

string 類

string 的常用操作

棧與佇列

(1) priority_queue

cpp-referencecplusplus

template<
    typename T,	// 型別
    typename Container = std::vector<T>,
    typename Compare = std::less<typename Container::value_type>
> class priority_queue;

優先佇列的底層實現是二叉堆,插入時,讓使 Compare 返回 true 的元素下沉(sink)

使用時容易模糊的就在於,Compare 怎麼定義(討論的是自定義型別,而非 POD)。一般的策略有:在型別中過載 < 運算子,則即可預設 compare,或定義仿函式

//(1) Comp預設,自定義型別中,過載或友元過載小於 < 運算子
struct ListNode {
    bool operator< (const ListNode&){}
    friend operator< (const ListNode&, const ListNode&){}
}
//(2) Comp為仿函式(即定義一個類Comp,然後過載它的括號運算子)
Class Comp{
    bool operator()(const T&, const T&){}}

常用的操作有push(), pop(), top(), empty()

集合 與 對映

(1) set

cpp-reference ⭐[set 部落格總結](c++ stl 庫中的 set - 然終酒肆 - 部落格園 (cnblogs.com))

template<
    typename Key,
    typename Compare = std::less<Key>,
    typename Allocator = std::allocator<Key>
> class multiset;

注意四個版本:set, multiset, unordered_set, unordered_multiset

預設有序是升序,(只需使用 rbegin()rend()就能的到逆序的)

常用操作:insert、find、count、clear、empty

(2) map

map 用法詳解

預設按關鍵字升序,STL 中的有序均是升序,因此需要過載的只是小於號 \(<\)

連結串列

(1) list
template<
    typename T,
    typename Allocator = std::allocator<T>
> class list;

雙向連結串列

front、back、push_back、pop_front、insert、erase、remove_if、sort、unique、reverse

(2) forward_list

單項鍊表

相關文章