日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

RTTI 简明

發(fā)布時(shí)間:2023/12/9 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 RTTI 简明 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

RTTI(Run-Time Type Identification)并不是什么新的東西,早在1993年,Bjarne Stroustrup已經(jīng)提出了RTTI的相關(guān)的功能建議.

什么是RTTI?
? ? ?在C++ 環(huán)境中﹐頭文件(header file) 含有類之定義(class definition)亦即包含有關(guān)類的結(jié)構(gòu)資料(representational information)。但是﹐這些資料只供編譯器(compiler)使用﹐編譯完畢后并未留下來(lái)﹐所以在執(zhí)行時(shí)期(at run-time) ﹐無(wú)法得知對(duì)象的類資料﹐包括類名稱、數(shù)據(jù)成員名稱與類型、函數(shù)名稱與類型等等。例如﹐兩個(gè)類Figure和Circle﹐其之間為繼承關(guān)系。?
若有如下指令﹕
Figure *p;
p = new Circle();
Figure &q = *p;
? ? 在執(zhí)行時(shí)﹐p指向一個(gè)對(duì)象﹐但欲得知此對(duì)象之類資料﹐就有困難了。同樣欲得知q 所引用對(duì)象的類資料﹐也無(wú)法得到。RTTI(Run-Time Type Identification)就是要解決這困難﹐也就是在執(zhí)行時(shí)﹐您想知道指針?biāo)傅交蛞玫降膶?duì)象類型時(shí)﹐該對(duì)象有能力來(lái)告訴您。隨著應(yīng)用場(chǎng)合之不同﹐所需支持的RTTI范圍也不同。

最單純的RTTI包括﹕?
類識(shí)別(class identification)──包括類名稱或ID。
繼承關(guān)系(inheritance relationship)──支持執(zhí)行時(shí)期的「往下變換類型」(downward casting)﹐亦即動(dòng)態(tài)變換類型(dynamic casting)

? ? 在對(duì)象數(shù)據(jù)庫(kù)存取上﹐還需要下述RTTI﹕?
對(duì)象結(jié)構(gòu)(object layout) ──包括屬性的類型、名稱及其位置(position或offset)。
成員函數(shù)表(table of functions)──包括函數(shù)的類型、名稱、及其參數(shù)類型等。
? ? 其目的是協(xié)助對(duì)象的I/O 和持久化(persistence) ﹐也提供調(diào)試訊息等。?
? ? ?若依照Bjarne Stroustrup 之建議〔注1 〕﹐C++ 還應(yīng)包括更完整的RTTI﹕?
●能得知類所實(shí)例化的各對(duì)象 。
●能參考到函數(shù)的源代碼。
●能取得類的有關(guān)在線說(shuō)明(on-line documentation) 。
? ? 其實(shí)這些都是C++ 編譯完成時(shí)所丟棄的資料﹐如今只是希望尋找個(gè)途徑來(lái)將之保留到執(zhí)行期間。然而﹐要提供完整的RTTI﹐將會(huì)大幅提高C++ 的復(fù)雜度﹗

RTTI可能伴隨的副作用
? ? ? RTTI最主要的副作用是﹕程序員可能會(huì)利用RTTI來(lái)支持其「復(fù)選」(multiple-selection)方法﹐而不使用虛函數(shù)(virtual function)方法。?
雖然這兩種方法皆能達(dá)到多態(tài)化(polymorphism) ﹐但使用復(fù)選方法﹐常導(dǎo)致違反著名的「開(kāi)放╱封閉原則」(open/closed principle) 〔注2 〕。反之﹐使用虛函數(shù)方法則可合乎這個(gè)原則.?
? ? ? Circle和Square皆是由Figure所派生出來(lái)的子類﹐它們各有自己的draw()函數(shù)。當(dāng)C++ 提供了RTTI﹐就可寫(xiě)個(gè)函數(shù)如下﹕?
void drawing( Figure *p )
{
? ? if( typeid(*p).name() == "Circle" )?
? ? ? ((Circle*)p) -> draw();?
? ? if( typeid(*p).name() == "Rectangle" )?
? ? ? ((Rectangle*)p) -> draw();?
}
? ? 雖然drawing() 函數(shù)也具有多型性﹐但它與Figure類體系的結(jié)構(gòu)具有緊密的相關(guān)性。當(dāng)Figure類體系再派生出子類時(shí)﹐drawing() 函數(shù)的內(nèi)容必須多加個(gè)if指令。因而違反了「開(kāi)放╱封閉原則」﹐如下﹕?
? ? 很顯然地﹐drawing() 函數(shù)應(yīng)加以修正。?
? ? 想一想﹐如果C++ 并未提供RTTI﹐則程序員毫無(wú)選擇必須使用虛函數(shù)來(lái)支持drawing() 函數(shù)的多型性。于是程序員將draw()宣告為虛函數(shù)﹐并寫(xiě)drawing() 如下﹕?
void drawing(Figure *p)
{ p->draw(); }
? ? 如此﹐Figure類體系能隨時(shí)派生類﹐而不必修正drawing() 函數(shù)。亦即﹐Figure體系有個(gè)穩(wěn)定的接口(interface) ﹐drawing() 使用這接口﹐使得drawing() 函數(shù)也穩(wěn)定﹐不會(huì)隨Figure類體系的擴(kuò)充而變動(dòng)。這是封閉的一面。而這穩(wěn)定的接口并未限制Figure體系的成長(zhǎng)﹐這是開(kāi)放的一面。因而合乎「開(kāi)放╱封閉」原則﹐軟件的結(jié)構(gòu)會(huì)更具彈性﹐更易于隨環(huán)境而不斷成長(zhǎng)。

RTTI的常見(jiàn)的使用場(chǎng)合
? ? 一般而言﹐RTTI的常見(jiàn)使用場(chǎng)合有四﹕異常處理(exceptions handling)、動(dòng)態(tài)轉(zhuǎn)類型(dynamic casting) 、模塊集成、以及對(duì)象I/O 。?
1.異常處理── 大家所熟悉的C++ 新功能﹕異常處理﹐其需要RTTI﹐如類名稱等。
2.動(dòng)態(tài)轉(zhuǎn)類型── 在類體系(class hierarchy) 中﹐往下的類型轉(zhuǎn)換需要類繼承的RTTI。
3.模塊集成── 當(dāng)某個(gè)程序模塊里的對(duì)象欲跟另一程序模塊的對(duì)象溝通時(shí)﹐應(yīng)如何得知對(duì)方的身分呢﹖知道其身分資料﹐才能呼叫其函數(shù)。一般的C++ 程序﹐常見(jiàn)的解決方法是──在源代碼中把對(duì)方對(duì)象之類定義(即存在頭文件里)包含進(jìn)來(lái)﹐在編譯時(shí)進(jìn)行連結(jié)工作。然而﹐像目前流行的主從(Client-Server) 架構(gòu)中﹐客戶端(client)的模塊對(duì)象﹐常需與主機(jī)端(server)的現(xiàn)成模塊對(duì)象溝通﹐它們必須在執(zhí)行時(shí)溝通﹐但又常無(wú)法一再重新編譯。于是靠標(biāo)頭文件來(lái)提供的類定義資料﹐無(wú)助于執(zhí)行時(shí)的溝通工作﹐只得依賴RTTI了。
4.對(duì)象I/O ── C++ 程序常將其對(duì)象存入數(shù)據(jù)庫(kù)﹐未來(lái)可再讀取之。對(duì)象常內(nèi)含其它小對(duì)象﹐因之在存入數(shù)據(jù)庫(kù)時(shí)﹐除了必須知道對(duì)象所屬的類名稱﹐也必須知道各內(nèi)含小對(duì)象之所屬類﹐才能完整地將對(duì)象存進(jìn)去。儲(chǔ)存時(shí)﹐也將這些RTTI資料連同對(duì)象內(nèi)容一起存入數(shù)據(jù)庫(kù)中。未來(lái)讀取對(duì)象時(shí)﹐可依據(jù)這些RTTI資料來(lái)分配內(nèi)存空間給對(duì)象。

RTTI從那里來(lái)?
? ? 上述談到RTTI的用途﹐以及其副作用。這眾多爭(zhēng)論﹐使得RTTI的標(biāo)準(zhǔn)遲遲未呈現(xiàn)出來(lái)。也導(dǎo)致各C++ 開(kāi)發(fā)環(huán)境提供者﹐依其環(huán)境所需而以各種方式來(lái)支持RTTI﹐且其支持RTTI的范圍也所不同。 目前常見(jiàn)的支持方式包括﹕?
●由類庫(kù)提供RTTI──例如﹐Microsoft 公司的Visual C++環(huán)境。
●由C++ 編譯器(compiler)提供──例如﹐Borland C++ 4.5 版本。
●由源代碼產(chǎn)生器(code generator)提供──例如Bellvobr系統(tǒng)。
●由OO數(shù)據(jù)庫(kù)的特殊預(yù)處理器(preprocessor)提供──例如Poet系統(tǒng)。
由程序員自己加上去。
? ? 這些方法皆只提供簡(jiǎn)單的RTTI﹐其僅為Stroustrup先生所建議RTTI內(nèi)涵的部分集合而已。相信不久的將來(lái)﹐會(huì)由C++ 編譯器來(lái)提供ANSI標(biāo)準(zhǔn)的RTTI﹐但何時(shí)會(huì)訂出這標(biāo)準(zhǔn)呢﹖ 沒(méi)人曉得吧﹗

程序員自己提供的RTTI
? ? 通常程序員自己可提供簡(jiǎn)單的RTTI﹐例如提供類的名稱或識(shí)別(TypeID)。最常見(jiàn)的方法是﹕為類體系定義些虛函數(shù)如Type_na() 及Isa() 函數(shù)等。請(qǐng)先看個(gè)例子﹕?
class Figure { };
class Rectangle : public Figure { };
class Square : public Rectangle
{

int data;
public:
Square() { data=88; }
void Display() { cout << data << endl; }
};
void main()
{

Figure *f = new Rectangle();
Square *s = (Square *)f;
s -> Display();
}
? ? 這時(shí)s 指向Rectangle 之對(duì)象﹐而s->Display()呼叫Square::Display() ﹐將找不到data值。若在執(zhí)行時(shí)能利用RTTI來(lái)檢查之﹐就可發(fā)出錯(cuò)誤訊息。于是﹐自行加入RTTI功能﹕?
class Figure
{

public:
? virtual char* Type_na() { return "Figure"; }?
? virtual int Isa(char* cna) { return !strcmp(cna, "Figure")? 1:0; }?
};

?

class Rectangle:public Figure
{ public:
? virtual char* Type_na() { return "Rectangle"; }?
? virtual int Isa(char* cna)? { return !strcmp(cna, "Rectangle")?1 : Figure::Isa(cna); }?
? static Rectangle* Dynamic_cast(Figure* fg) { return fg -> Isa(Type_na())?(Rectangle*)fg : 0; }?
};

?

class Square:public Rectangle
{

int data;
public:
Square() { data=88; }
? virtual char* Type_na() { return "Square"; }?
? virtual int Isa(char* cna) { return !strcmp(cna, "Rectangle")? 1 : Rectangle::Isa(cna); }?
? static Square* Dynamic_cast(Figure *fg)? { return fg->Isa(Type_na())? (Square*)fg : 0; }?
? void Display() { cout << "888" << endl; }?
};
? ? 虛函數(shù)Type_na() 提供類名稱之RTTI﹐而Isa() 則提供繼承之RTTI﹐用來(lái)支持「動(dòng)態(tài)轉(zhuǎn)類型」函數(shù)──Dynamic_cast()。例如﹕?
Figure *f = new Rectangle();
cout << f -> Isa("Square") << endl;
cout << f -> Isa("Figure") << endl;
? ? 這些指令可顯示出﹕f 所指向之對(duì)象并非Square之對(duì)象﹐但是Figure之對(duì)象(含子孫對(duì)象)。再如﹕
Figure *f; Square *s;
f = new Rectangle();
s = Square == Dynamic_cast(f);
if(!s)
cout << "dynamic_cast error!!" << endl;
此時(shí)﹐依RTTI來(lái)判斷出這轉(zhuǎn)類型是不對(duì)的。

?

類庫(kù)提供RTTI
? ? 由類庫(kù)提供RTTI是最常見(jiàn)的﹐例如Visual C++的MFC 類庫(kù)內(nèi)有個(gè)CRuntimeClass 類﹐ 其內(nèi)含簡(jiǎn)單的RTTI。請(qǐng)看個(gè)程序﹕?
class Figure:public CObject
{
DECLARE_DYNAMIC(Figure);
};
class Rectangle : public Figure
{
DECLARE_DYNAMIC(Rectangle);
};
class Square : public Rectangle
{
DECLARE_DYNAMIC(Square);
int data;
public:
void Display() { cout << data << endl; }
Square() { data=88; }
};
IMPLEMENT_DYNAMIC(Figure, CObject);
IMPLEMENT_DYNAMIC(Rectangle, Figure);
IMPLEMENT_DYNAMIC(Square, Rectangle);
? ? Visual C++程序依賴這些宏(Macor) 來(lái)支持RTTI?,F(xiàn)在就看看如何使用CRuntimeClass類吧﹗如下﹕?
CRuntimeClass *r;
Figure *f = new Rectangle();
r = f->GetRuntimeClass();
cout << r->m_psClassName << endl;
? ? ? 這就在執(zhí)行時(shí)期得到類的名稱。Visual C++的類庫(kù)僅提供些較簡(jiǎn)單的RTTI──類名稱、對(duì)象大小及父類等。至于其它常用的RTTI如──數(shù)據(jù)項(xiàng)的類型及位置(position)等皆未提供。

?

C++編譯器提供RTTI
? ? 由C++ 語(yǔ)言直接提供RTTI是最方便了﹐但是因RTTI的范圍隨應(yīng)用場(chǎng)合而不同﹐若C++語(yǔ)言提供所有的RTTI﹐將會(huì)大幅度增加C++ 的復(fù)雜度。目前﹐C++ 語(yǔ)言只提供簡(jiǎn)單的RTTI﹐ C++ 新增typeid()操作數(shù)以及dynamic_cast<T*>函數(shù)模版。

為了獲得一個(gè)對(duì)象的類型可以使用typeid函數(shù),該函數(shù)反回一個(gè)對(duì)type_info類對(duì)象的引用,要使用typeid必須使用頭文件<typeinfo>,因?yàn)閠ypeid是一個(gè)返回類型為typ_info的引用的函數(shù)?

?

?cout<<typeid(A).name();

cout<<typeid(A).raw_name();

?

請(qǐng)看個(gè)程序﹕?
class Figure
{

public:
virtual void Display();
};
class Rectangle : public Figure { };
class Square:public Rectangle
{

int data;
public:
Square() { data=88; }
void Display() { cout << data << endl; }
};
? ? 現(xiàn)在看看如何使用typeid()操作數(shù)──?
Figure *f = new Square();
const type_info ty = typeid(*f);
cout << ty.name() << endl;
? ? 這會(huì)告訴您﹕f 指針?biāo)傅膶?duì)象﹐其類名稱是Square。再看看如何使用dynamic_cast<T*>函數(shù)樣版──?
Figure *f; Square *s;
f = new Rectangle();
s = dynamic_cast<Sqiare *>(f);
if(!s)
cout << "dynamic casting error!!" << endl;
? ? 在執(zhí)行時(shí)﹐發(fā)現(xiàn)f 是不能轉(zhuǎn)為Square *類型的。如下指令﹕?
Figure *f; Rectangle *r;
f = new Square();
r = dynamic_cast<Rectangle *>(f);
if(r)

r->Display();
這種類型轉(zhuǎn)換是對(duì)的。
RTTI與虛函數(shù)表
? ? 在C++ 程序中﹐若類含有虛函數(shù)﹐則該類會(huì)有個(gè)虛函數(shù)表(Virtual Function Table﹐ 簡(jiǎn)稱VFT )。為了提供RTTI﹐C++ 就將在VFT 中附加個(gè)指針﹐指向typeinfo對(duì)象﹐這對(duì)象內(nèi)含RTTI資料.?
? ? 由于該類所實(shí)例化之各對(duì)象﹐皆含有個(gè)指針指向VFT 表﹐因之各對(duì)象皆可取出typeinfo對(duì)象而得到RTTI。例如﹐?
Figure *f1 = new Square();
Figure *f2 = new Square();
const typeinfo ty = typeid(*f2);
其中﹐typeid(*f2) 的動(dòng)作是﹕
1.取得f2所指之對(duì)象。
2.從對(duì)象取出指向VMF 之指針﹐經(jīng)由此指針取得VFT 表。
3.從表中找出指向typeinfo對(duì)象之指針﹐經(jīng)由此指針取得typeinfo對(duì)象。
? ? ?這typeinfo對(duì)象就含有RTTI了。經(jīng)由f1及f2兩指針皆可取得typeinfo對(duì)象﹐所以 typeid(*f2) == typeid(*f1)。?
總結(jié)
? ? RTTI是C++ 的新功能。過(guò)去﹐C++ 語(yǔ)言來(lái)提供RTTI時(shí)﹐大多依賴類庫(kù)來(lái)支持﹐但各類庫(kù)使用的方法有所不同﹐使得程序的可移植性(portability) 大受影響。然而﹐目前C++ 也只提供最簡(jiǎn)單的RTTI而已﹐可預(yù)見(jiàn)的未來(lái)﹐當(dāng)大家對(duì)RTTI的意見(jiàn)漸趨一致時(shí)﹐C++ 將會(huì)提供更完整的RTTI﹐包括數(shù)據(jù)項(xiàng)和成員函數(shù)的類型、位置(offset)等資料﹐使得C++ 程序更井然有序﹐易于維護(hù)。?

轉(zhuǎn)載于:https://www.cnblogs.com/EnoroF/archive/2012/06/30/2566613.html

總結(jié)

以上是生活随笔為你收集整理的RTTI 简明的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。