国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

細談C++多態性的“動”與“靜”

2019-11-17 05:28:08
字體:
來源:轉載
供稿:網友

  在我們討論多態的時候,先看看什么是硬編碼和軟編碼:硬編碼就是把代碼寫死了,導致彈性不足,降低了可擴展性,例如在代碼里的
if...else...;switch...case...

  這些代碼通常都屬于硬編碼,項目中的這些代碼多了,就相當于說明這個代碼的靈活性、擴展性、彈性等等的少了。

  所以,我們要盡量使用軟編碼,通俗點就是“別把話說死了,留點轉彎的余地”。多態性就是這種軟編碼特性的反映,下面我們一起來研究一下多態性。

  多態性是一種抽象,把事物的特征抽象出來,然后事物的具體形態我們就不關心了。

  例如對工人這種事物來說,他的特征就是工作,至于是什么工人,他做什么工作,我們就不用關心了,只要我們以“工人.工作”這種方式去調用。那他就會為我們工作了。

  那為什么我們不抽象出其他的特征,只抽象出工作這個特征呢?因為我們只對這個特征感愛好,他的什么吃飯、睡覺、如廁等的特性我們都不關心了。有了多態,我們就可以實現軟編碼了!

  講解了多態的概念之后,我們來看看多態的實現(C++的實現):

  多態的實現是通過虛函數表(VTable),每個類假如有虛函數,那它就有一個虛函數表,所有的對象都共享這一個VTable。這個概念也叫做動態聯編,還有靜態聯編,這些概念都是通過在程序執行的時候表現出來的性質來定的,我們下面會看看它的“動”和“靜”究竟體現在哪里。

  先看一段代碼:

class C0
...{
public:
void Test()
...{
cout << "call C0 Test()。" << endl;
}
};
  這個類沒有虛函數,調用的時候就是靜態調用。調用的代碼如下:

// 靜態編譯(早綁定 early binding)
C0 *pO0;
C0 obj0;
pO0 = &obj0;
pO0->Test();
它的反匯編代碼如下:

// 直接調用函數(已經知道地址)
00401432 mov ecx,dWord ptr [ebp-0Ch]
00401435 call @ILT+160(C0::Test) (004010a5)
下面看看帶虛函數的類:

class C1
...{
public:
virtual void Test()
...{
cout << "call C1 Test()" << endl;
}
};

class C11 : public C1
...{
public:
void Test()
...{
cout << "call C11 Test()" << endl;
}
};
  它的調用:

C11 obj11;

C1 *pObj1;
pObj1 = &obj11;
// 這里生成的匯編代碼
// 0040144A lea edx,[ebp-14h] // 尋址找到pObj1
// 0040144D mov dword ptr [ebp-1Ch],edx

pObj1->Test();
// 這里生成的匯編代碼
// 00401450 mov eax,dword ptr [ebp-1Ch] // 取得虛表地址
// 00401453 mov edx,dword ptr [eax]
// 00401455 mov esi,esp
// 00401457 mov ecx,dword ptr [ebp-1Ch] // 根據虛表的位置來取得Test()函數
// 0040145A call dword ptr [edx] // 調用Test()函數
  根據上述的匯編代碼,我們可以知道,在多態調用函數的時候,程序執行以下步驟:

  1、尋址找到pObj1

  2、由于C11重載了Test虛函數,所以*pObj1指向的就是C11的VTable的地址

  3、調用pObj1->Test()時,程序通過Vptr(虛表的指針,對象的首地址),找到VTable,再根據偏移調用Test函數。

  由于上述的多態調用過程是一個動態的過程(在運行時去“找”函數來調用),而不是編譯完就直接把函數地址擺在那里了,所以被稱作“動態聯編”。

  上面把多態的“動”和“靜”的特點結合代碼說了一遍,希望能說清楚了。

  下面再驗證一個類的虛表的問題,假如你對虛表已經很熟悉了,就不用再往下看了。

  在很多書上都已經說明了C++的對象模型,這里只是做個驗證。看看這段代碼:

class C1
...{
public:
virtual void Test()
...{
cout << "call C1 Test()" << endl;
}
};

class C11 : public C1
...{
public:
void Test()
...{
cout << "call C11 Test()" << endl;
}
};

class C12 : public C1
...{
public:
void Test()
...{
cout << "call C12 Test()" << endl;
}
};
  我們可以知道 Test() 是虛函數,從C1派生的類必定有自己的虛表。而且根據別的資料,虛表指針是放在對象的首地址的,我們下面就來驗證一下:


// 驗證首地址
C11 obj110;
C11 obj111;

printf("obj111 的地址:%x ", &obj111);
printf("obj110 虛表的地址:%x ", *(&obj110));
printf("obj111 虛表的地址:%x ", *(&obj111));
  結果是:

  obj110 的地址:12ff7c
  obj111 的地址:12ff78
  obj110 虛表的地址:432098
  obj111 虛表的地址:432098

  由上面的結果我們可以驗證:

  1、一個類一個VTABLE,而不是一個對象一個VTABLE。

  2、對象的首地址的內容就是VTABLE的地址。

  總結一下:

  C++的多態性包括其概念和實現,本文從編譯器生成的代碼來討論C++多態特性,非凡說明了為什么多態特性被稱為“動態聯編”,它和“靜態聯編”有什么不同,它們的“動”與“靜”體現在哪里。另外還對對象的虛表做了些驗證。好了,希望本文能對你熟悉C++的多態性有一定的幫助!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 龙江县| 海安县| 通河县| 蒙阴县| 积石山| 九寨沟县| 酒泉市| 泗阳县| 醴陵市| 安宁市| 武夷山市| 离岛区| 科技| 乌拉特后旗| 灵川县| 清苑县| 玉山县| 婺源县| 克山县| 泰州市| 东安县| 太白县| 东城区| 明星| 金堂县| 广汉市| 临澧县| 吉安市| 东乡县| 渑池县| 阿瓦提县| 丰县| 榆林市| 定兴县| 盈江县| 正定县| 西乌| 东海县| 密山市| 宁阳县| 塔河县|