概述面向?qū)ο笳Z言的重要概念和實(shí)現(xiàn)技術(shù)
以C++語言為例,介紹如何將C++程序翻譯成C程序
實(shí)際的編譯器大都把C++程序直接翻譯成低級(jí)語言程序
編譯器對(duì)于繼承的處理,往往是父類包含子類的對(duì)象,例如
struct Base
{
int a;
};
struct Derived
{
Base base;
int b;
};
再深入的偶也不會(huì)了.........
下面我們討論對(duì)面向?qū)ο蠖鄳B(tài)特性的處理。多態(tài)是面向?qū)ο笳Z言最為精彩的地方,可以說是誕生無數(shù)神奇的特性,多態(tài)給了我們極大的自由,讓我們可以在一套類的體系結(jié)構(gòu)中自由游走,可以寫很少的代碼,但是完成復(fù)雜的功能,可以在別人的基礎(chǔ)上做二次開發(fā)......
好了,不打廣告了,下面舉一個(gè)簡單的例子說明編譯器對(duì)多態(tài)的處理。首先介紹一下虛函數(shù)表。大多數(shù)編譯器實(shí)現(xiàn)多態(tài)都是通過虛函數(shù)表,虛函數(shù)表是一個(gè)保存了多個(gè)函數(shù)指針的表,其中每個(gè)函數(shù)對(duì)應(yīng)著一個(gè)虛函數(shù)(非虛函數(shù)不參與),調(diào)用一個(gè)虛函數(shù)的時(shí)候,編譯器通過虛函數(shù)表查找相應(yīng)位置的函數(shù),所以編譯時(shí)編譯器不知道這個(gè)函數(shù)會(huì)調(diào)用到基類的函數(shù)還是派生類的函數(shù),所以叫動(dòng)態(tài)綁定或運(yùn)行時(shí)綁定。
以下是一個(gè)簡單的多態(tài)實(shí)例程序,有了虛函數(shù)所以可以在基類指針指向派生類對(duì)象的時(shí)候運(yùn)行派生類的函數(shù)。
#include <iostream>
using namespace std;
class Base
{
public:
virtual void Hello();
};
void Base::Hello()
{
cout<<"Hello in Base"<<endl;
}
class Derived:public Base
{
public:
void Hello();
};
void Derived::Hello()
{
cout<<"Hello in Derived"<<endl;
}
int main()
{
Base* p=new Base;
p->Hello();//Hello in Base
p=new Derived;
p->Hello();//Hello in Derived
return 0;
}
---------------------------------------我是華麗的分割線------------------------------------
以下是對(duì)應(yīng)的翻譯結(jié)果,但是需要注意的是這僅僅是一個(gè)示例,首先pFun這個(gè)函數(shù)指針無法指向所有類型的函數(shù),而且按照上篇文章所述,翻譯Hello()函數(shù)的時(shí)候至少應(yīng)該在參數(shù)里加一個(gè)本身的引用的....深入的我也不會(huì)了.....
#include <iostream>
using namespace std;
typedef void (*pFun)();//定義函數(shù)指針
void Base_Hello()//基類虛函數(shù)
{
cout<<"Hello in Base"<<endl;
}
pFun Base_vtf[1]={Base_Hello};//Base的虛函數(shù)表,編譯器自動(dòng)把所有virtual的函數(shù)生成一個(gè)虛函數(shù)表
struct Base
{
Base(){vft=Base_vtf;}
pFun* vft;//虛函數(shù)表指針
};
void Derived_Hello()//父類覆蓋基類的函數(shù)
{
cout<<"Hello in Derived"<<endl;
}
pFun Derived_vtf[1]={Derived_Hello};//Derived的虛函數(shù)表
//編譯器會(huì)首先復(fù)制基類的虛函數(shù)表,然后把被覆蓋的虛函數(shù)用父類的虛函數(shù)代替
//然后加入父類的虛函數(shù)
struct Derived
{
Derived(){vft=Derived_vtf;}
pFun* vft;
};
int main()
{
//編譯器會(huì)把非虛函數(shù)的引用直接翻譯成對(duì)應(yīng)的函數(shù)調(diào)用
//而虛函數(shù)則按照虛函數(shù)表取相應(yīng)的函數(shù),這樣如果基類指針指向派生類
//那么派生類的虛函數(shù)表中相應(yīng)位置已經(jīng)被派生類的方法覆蓋了,從而可以調(diào)用到派生類的方法
Base* p=new Base;
p->vft[0]();//Hello in Base
p=(Base*)new Derived;
p->vft[0]();//Hello in Derived
return 0;
}
從上面我們可以大致了解多態(tài)的處理過程和虛函數(shù)表的作用。我們可以用VC驗(yàn)證一下虛函數(shù)表。
設(shè)我們有這樣的一個(gè)類:
class Base {
public:
virtual void f() { cout << "Base::f" << endl; }
virtual void g() { cout << "Base::g" << endl; }
virtual void h() { cout << "Base::h" << endl; }
};
按照上面的說法,我們可以通過Base的實(shí)例來得到虛函數(shù)表。 下面是實(shí)際例程:
typedef void(*Fun)(void);
Base b;
Fun pFun = NULL;
cout << "虛函數(shù)表地址:" << (int*)(&b) << endl;
cout << "虛函數(shù)表 — 第一個(gè)函數(shù)地址:" << (int*)*(int*)(&b) << endl;
// Invoke the first virtual function
pFun = (Fun)*((int*)*(int*)(&b));
pFun();
實(shí)際運(yùn)行經(jīng)果如下:(Windows XP+VS2003, Linux 2.6.22 + GCC 4.1.3)
虛函數(shù)表地址:0012FED4
虛函數(shù)表 — 第一個(gè)函數(shù)地址:0044F148
Base::f
通過這個(gè)示例,我們可以看到,我們可以通過強(qiáng)行把&b轉(zhuǎn)成int *,取得虛函數(shù)表的地址,然后,再次取址就可以得到第一個(gè)虛函數(shù)的地址了,也就是Base::f(),這在上面的程序中得到了驗(yàn)證(把int* 強(qiáng)制轉(zhuǎn)成了函數(shù)指針)。通過這個(gè)示例,我們就可以知道如果要調(diào)用Base::g()和Base::h(),其代碼如下:
(Fun)*((int*)*(int*)(&b)+0); // Base::f()
(Fun)*((int*)*(int*)(&b)+1); // Base::g()
(Fun)*((int*)*(int*)(&b)+2); // Base::h()
以上引用自:http://www.cppblog.com/xczhang/archive/2008/01/20/41508.html非常感謝作者
下面這篇文章是使用VCdebug窗口觀察虛函數(shù)的,也很不錯(cuò),一并感謝作者
http://www.cnblogs.com/wirelesser/archive/2008/03/09/1097463.html
總結(jié):本文針對(duì)面向?qū)ο蟮亩鄳B(tài)特性和繼承特性,介紹了面向?qū)ο笳Z言的編譯過程。我們可以得到如下啟示:
多態(tài)是通過虛函數(shù)表實(shí)現(xiàn)的,實(shí)際如果我們用sizeof看一個(gè)類的長度的話,會(huì)發(fā)現(xiàn)該長度實(shí)際由所有非靜態(tài)成員和虛函數(shù)表(四個(gè)字節(jié)的指針)構(gòu)成.
由此我們對(duì)多態(tài)有了更深刻的理解.
文章出處:http://www.cnblogs.com/sdqxcxh/ 作者:布拉德比特