第四周 C++面向?qū)ο蟾呒?jí)編程(下)Boolan

1. 導(dǎo)讀

我們的目標(biāo)

  • 在先前基礎(chǔ)課程所培養(yǎng)的正規(guī)、大氣的編程素養(yǎng)上,繼續(xù)探討更多技術(shù)。
  • 泛型編程(Generic Programming)和面向?qū)ο缶幊蹋∣bject-Oriented Programming)雖然分屬不同思維,但它們正是 C++的技術(shù)主線,所以本課程也討論template(模板)。
  • 深入探索面向?qū)ο蟮睦^承關(guān)系(inheritance)所形成的對(duì)象模型(Object Model),包括隱藏于底層的 this 指針,vptr(虛指針),vtbl(虛表),virtual mechanism(虛機(jī)制),以及虛函數(shù)(virtual functions)造成的 polymorphism(多態(tài))效果。

2. 類(lèi)型轉(zhuǎn)換

轉(zhuǎn)換有兩種,一種是轉(zhuǎn)出去,一種是轉(zhuǎn)過(guò)來(lái)。

2.1 Conversion Function 轉(zhuǎn)換函數(shù)

轉(zhuǎn)換函數(shù)的作用是轉(zhuǎn)出去,把這個(gè)類(lèi)的值轉(zhuǎn)換成其他的類(lèi)型。


Conversion Function
operator double() const {……;}

定義了一個(gè)轉(zhuǎn)換為 double 的函數(shù),
沒(méi)有參數(shù),轉(zhuǎn)換時(shí)不會(huì)帶有參數(shù)。
不寫(xiě)返回類(lèi)型,返回類(lèi)型就是名稱(chēng)里這個(gè)double

  • 如果不改變值,就該加 const,否則后面可能會(huì)出錯(cuò)。
  • 只要認(rèn)為合理,可以設(shè)計(jì)好幾個(gè)轉(zhuǎn)換函數(shù)。

模板的偏特化?
操作符重載

2.2 只有一個(gè)參數(shù)的構(gòu)造函數(shù)

只有一個(gè)參數(shù)的構(gòu)造函數(shù)可以將一個(gè) int 或 float 值轉(zhuǎn)換為該類(lèi)對(duì)象。

2.2.1 non-explicit-on-argument ctor

non-explicit-on-argument ctor
Fraction (int num, int den=1): m_numerator(num), m_denominator(den) { }

分母默認(rèn)是1,這樣一個(gè)值構(gòu)造為對(duì)象時(shí),實(shí)際值不變。

Fraction operator+(const Fraction& f) { }

只能分?jǐn)?shù)加分?jǐn)?shù)

Fraction d2=f+4;

4可以轉(zhuǎn)換為 Fraction,因?yàn)橛幸粋€(gè)構(gòu)造函數(shù)只有一個(gè)int 參數(shù)。

2.2.2 conversion function vs. non-explicit-one argument ctor

conversion function vs. non-explicit-one argument ctor

當(dāng)轉(zhuǎn)換函數(shù)與非顯式聲明的一個(gè)參數(shù)的構(gòu)造函數(shù)同時(shí)存在時(shí),就會(huì)出現(xiàn)歧義。因?yàn)閮煞N方式都可以編譯。
多于一條路徑可以編譯,就會(huì)出現(xiàn)歧義,編譯器就會(huì)報(bào)錯(cuò)。

[Error] ambiguous

2.2.3 explicit-one-argument ctor

explicit-one-argument ctor

顯式聲明就可以避免這個(gè)問(wèn)題。

explicit Fraction(int num, int den=1):……

此時(shí)就會(huì)調(diào)用構(gòu)造函數(shù),而不會(huì)調(diào)用 double 轉(zhuǎn)換函數(shù)。

conversion function

3. 模仿的類(lèi)

3.1 pointer-like classes

設(shè)計(jì)一個(gè)類(lèi),模擬 pointer

3.1.1 關(guān)于智能指針

不同的語(yǔ)法

->用掉后,還有一個(gè)->,所以

sp->method();
px->method(); //轉(zhuǎn)換完依舊有->

3.1.2 關(guān)于迭代器

迭代器中的指針操作

注意操作符重載
++ -- 適用于指針移動(dòng)
Paste_Image.png

return (*node).data;  //取的是node 指向的塊的數(shù)據(jù)
return &(operator()); //返回迭代器中內(nèi)容的指針,而不是指向迭代器塊的 node 的指針。

3.2 function-like classes,所謂仿函數(shù)

function-like classes
Paste_Image.png
Paste_Image.png
Paste_Image.png

unary_function 一個(gè)操作數(shù)
binary_function 兩個(gè)操作數(shù)

4. namespace 經(jīng)驗(yàn)談

namespace
namespace jj01
{
}//namespace

5. 模板 template

5.1 class template

class template
template<typename T>

5.2. Function Template

Function Template
template <class T>

5.3 Member Template

Member Template
template <class T1, class T2>
struct pair {
……
  template <class U1, class U2>
  ……
}
Paste_Image.png
Paste_Image.png
Base1* ptr = new Derived1; //up-cast
shared_ptr<Base1>sptr(new Derived1); // 模擬 up-cast

5.4 specialization,模板特化

specialization
template<class Key>
struct hash {  } ;
template<>
struct hash<char> {   };

泛化對(duì)應(yīng)特化,共性中的個(gè)性,用來(lái)應(yīng)對(duì)特例。

5.4.1 partial specialization,模板偏特化

又稱(chēng)為局部特化

5.4.1.1 個(gè)數(shù)的偏

Paste_Image.png

< >尖括號(hào)內(nèi)叫做模板參數(shù)

class vector<bool, Alloc> { };   // Alloc沒(méi)改變,而 bool 設(shè)定了。

一定要從左到右,不能跳,不能135固定,24改變。

5.4.1.2 范圍的偏

范圍的偏

指針指向的偏

class c<T*> {   };  // 限定為指針

如果 T 是指針,使用偏特化模板。

5.5 template template parameter,模板模板參數(shù)

5.5.1 容器需要參數(shù)

容器需要參數(shù)
using Lst = list<T, allocator<>>;

模板需要好幾個(gè)參數(shù),必須替換

5.5.2 智能指針

智能指針

對(duì)應(yīng) SmartPtr,可以是……,不可以是……

5.5.3 這不是模板模板參數(shù)

這不是模板模板參數(shù)

已經(jīng)綁定了,必須是這個(gè),所以就沒(méi)有模糊地帶了。

6. 關(guān)于 C++ 標(biāo)準(zhǔn)庫(kù)

Paste_Image.png

所有的容易算法都要用一遍。
編譯器需要設(shè)定到 C++ 11

6.1 variadic templates (since C++11)

variadic templates

6.2 auto (since C++11)

auto

用 auto 時(shí)一定要讓編譯器能推出來(lái)。

auto ite = find(……)

find 的類(lèi)型就是 auto 給 ite 的類(lèi)型。


Paste_Image.png

auto 不能亂用,太長(zhǎng)了、寫(xiě)不出來(lái)可以用。
我們一定要知道每個(gè)變量的定義是什么。

ranged-bas for (since C++11)

ranged-bas for
for ( decl : coll ) //左邊是一個(gè)變量,右邊必須是一個(gè)collector,容器
for ( int i : { 2, 3, 5, 7 } ){ }
vector<double> vec;
……
for ( auto elem : vec ) { cout << elem << endl ;} //傳值
for ( auto& elem : vec ) { elem *= 3; } //傳引用,盡量傳引用

15. reference(引用)

reference

聲明時(shí)一定要有初值,設(shè)完之后就不能再變了。


reference

object 和其 reference 的大小相同,地址也相同(全都是假象)
???那么新建一個(gè) reference 會(huì)讓程序新占用多少內(nèi)存呢?

常見(jiàn)用途

常見(jiàn)用途

函數(shù)傳參

void func3(Cls& obj) { obj.xxx(); }
func3(obj);

reference 通常不用于聲明變量,而用于參數(shù)類(lèi)型和返回類(lèi)型的描述。
相同聲明結(jié)構(gòu),僅僅傳遞引用和變量,會(huì)導(dǎo)致模糊,簽名相同,所以不能同時(shí)存在。
是否加const,
???有什么區(qū)別?
加 const 會(huì)改變簽名,是可以定義的。

7. 復(fù)合&繼承關(guān)系下的構(gòu)造和析構(gòu)

7.1 Composition(復(fù)合)關(guān)系下的構(gòu)造和析構(gòu)

Composition(復(fù)合)關(guān)系下的構(gòu)造和析構(gòu)

Container 在外 Component 在內(nèi)

7.2 Inheritance(繼承)關(guān)系下的構(gòu)造和析構(gòu)

Inheritance(繼承)關(guān)系下的構(gòu)造和析構(gòu)

Derive在外,Base 在內(nèi)
由內(nèi)而外構(gòu)建
由外而內(nèi)析構(gòu)
子類(lèi)析構(gòu)函數(shù)會(huì)自動(dòng)調(diào)用父類(lèi)析構(gòu)函數(shù)

Inheritance + Composition 關(guān)系下的構(gòu)造和析構(gòu)

Inheritance + Composition 關(guān)系下的構(gòu)造和析構(gòu)

不同編譯器可能不同
觀察到的結(jié)論是先調(diào)用 Base,后調(diào)用 Component

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容