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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

C++之 RTTI

發(fā)布時間:2025/1/21 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++之 RTTI 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

什么是 RTTI

RTTI(Runtime Type Indentification) 即運行階段類型識別。 這是 C++新引進的特性之一。RTTI旨在為程序在運行階段確定對象的類型提供一種標準方式。

RTTI 用途

考慮一種情況:假如現在有一個基類 Base,并且基類中包含有虛函數 Fun1,然后派生類 A 繼承于基類 Base,并實現基類的虛函數Fun1,同時,派生類 A 又定義一個虛函數 Fun2,接著,派生類 B 繼承于 A,并且實現了基類中的兩個虛函數 Fun1和 Fun2,那么,當我們選擇一個類 A 或 B,創(chuàng)建一個對象,并將指針賦值給基類指針,這時候,當我們要用改指針的時候就不知道該指針真正指向哪個對象。
那么問題來了,可能你會問,干嘛要知道該指針類型呢?如果說通過該指針去調用基類本身就有的虛函數,則可以正常調用,不需要知道對象的類型,但是當調用派生類中新定義的函數,這時候就會出錯啦。這種情況下,只有某些類型的對象可以使用該方法。所以就需要進行判斷對象類型,或者進行相應的強制合理轉換對象類型。

光是描述可能太難理解,現在咱來看看實際的例子:

#include <iostream>using namespace std;class Base { public:virtual void Fun1(){}virtual ~Base(); };class A : public Base { public:virtual void Fun1(){}virtual void Fun2(){}virtual ~A(); };class B :public A { public:void Fun1(){}void Fun2(){}virtual ~B(); };int main() {Base * p1;Base * p2;Base * p3;p1 = new Base();p2 = new A();p3 = new B();p2->Fun1();//right // p2->Fun2();//error..p3->Fun1();//right // p3->Fun2();//error..return 0; }Base::~Base(){}A::~A(){}B::~B(){}

上例子可以看到,p2->Fun2()以及p3->Fun2()是會報錯的,因 Fun2()是在 A 類中定義的,而 p2指針是賦給基類 Base 的,Base 中并沒有 Fun2()函數。

對于這種問題,RTTI 提供了解決方案。

C++中三個支持 RTTI 的元素

  • dynamic_cast :改運算符將使用一個指向基類的指針來生成一個指向派生類的指針。如果轉換不合理,會轉換失敗,并返回0—空指針。
  • typeid:運算符返回一個指出對象的類型的值。
  • type_info:存儲了有關特定類型的信息。

注意:RTTI 只適用于包含虛函數的類。只能講 RTTI 用于包含虛函數的類層次結構,原因在于只有對于這種類層次結構,才應將派生對象的地址賦給基類指針。

dynamic_cast

dynamic_cast運算符是最常見的 RTTI 組件,它可以安全地將對象的地址賦給特定類型的指針。

還是根據以上示例,咱們來看以下幾個轉換是否安全:

Base * pBase = new Base(); A * pA = new A(); B * pB = new B();B * p1 = (B*)pB; //#1 B * p2 = (B*)pBase; //#2 A * p3 = (B*)pB; //#3

上面示例中#2是不安全的,因為只有那些指針類型與對象的類型(或對象的直接或間接基類的類型)相同的類型轉換才一定是安全的。#2的轉換中,希望將基類指針轉換成派生類指針,但是由于基類指針 Base 中并不具有 B 類中的 Fun2()函數,所以這個轉換就是不安全的。而#1和#3可以安全轉換。

那么,我們怎么來檢查這些轉換是否安全呢?這時候dynamic_cast就排上用場了。
看一個通用的轉換示例:

dynamic_cast<Type *>(pt)

如果只想的對象(*pt)的類型為 Type 或者從 Type 直接或間接派生而來的類型,則以上表達式將指針 pt 轉換成 Type 類型的指針,否則,轉換失敗,返回空指針0.

也就是說dynamic_cast會在轉換的時候動態(tài)的進行類型安全檢查,如果該轉換安全,那么就正常轉換,如果不安全,就返回空指針。

我們在將上面的#2表達式修改如下:

B * p2 = dynamic_cast<B*>(pBase);

這個轉換不安全,所以p2的值為空。

OK,接下來看一個正式的例子:

#include <iostream> #include <cstdlib> #include <ctime>using namespace std;class Grand { public:Grand(int h = 0):hold(h){}virtual void Speak() const {cout << "I'm a grand class! \n";}virtual int Value() const{return hold;}virtual ~Grand(); private:int hold; };class Superb : public Grand { public:Superb(int h = 0):Grand(h){}void Speak() const {cout << "I'm a superb class \n";}virtual void Say() const{cout << "I hold the superb value of " << Value() << "!\n";}virtual ~Superb();};class Magnificent: public Superb { public:Magnificent(int h = 0,char c = 'A'): Superb(h), ch(c){}void Speak() const {cout << "I'm a magnificent class !!\n";}void Say() const {cout << "I hold the character" << ch<< "and the integer " << Value() << "!\n";}private:char ch; };Grand * GetOne() {Grand * p = nullptr;switch(std::rand() %3){case 0: p = new Grand(std::rand() % 100);break;case 1: p = new Superb(std::rand() % 100);break;case 2: p = new Magnificent(std::rand() % 100,'A' + std::rand() % 26);break;}return p; }int main() {std::srand(std::time(0));Grand * pg;Superb * ps;for(int i = 0 ; i < 5 ; i++){pg = GetOne();pg->Speak();if(ps = dynamic_cast<Superb*>(pg)){ps->Say();}}return 0; }Grand::~Grand(){}Superb::~Superb(){}

輸出:

I'm a grand class! I'm a superb class I hold the superb value of 64! I'm a magnificent class !! I hold the characterUand the integer 71! I'm a grand class! I'm a magnificent class !! I hold the characterCand the integer 51!

這個示例中,GetOne()方法隨機創(chuàng)建一個指針,并賦值給基類Grand指針,在 main 函數中pg->Speak();可以正常調用,是因為 Speak()方法本身就是在基類中定義的,而Say()方法是在派生類中定義的,基類指針無法調用,所以這里加入了動態(tài)轉換 dynamic_cast<Superb*>(pg),如果轉換合法,將會正常調用 Say()方法,如果不合法,則返回空指針。

所以根據輸出結果我們看到,如果隨機創(chuàng)建出來的是基類指針,那么不會調用 Say()方法。

typeid運算符和 type_info類

typeid運算符使得能夠確定兩個對象是否為同種類型。它可以接受兩種參數:

  • 1.類名
  • 2.結果為對象的表達式

typeid 運算符返回一個對type_info對象的引用,其中,type_info是在頭文件 typeinfo 中定義的一個類。type_info類重載了==和 != 運算符,以便可以使用這些運算符來對類型進行比較。

OK,接下來將上面的示例修改一下:

int main() {std::srand(std::time(0));Grand * pg;Superb * ps;for(int i = 0 ; i < 5 ; i++){pg = GetOne();pg->Speak();if(ps = dynamic_cast<Superb*>(pg)){ps->Say();}//類型判斷if(typeid (Magnificent) == typeid (*pg)){cout<< "Yes, you are really Manificent.\n";}}return 0; }

運行結果:

I'm a grand class! I'm a magnificent class !! I hold the characterBand the integer 32! Yes, you are really Manificent. I'm a grand class! I'm a magnificent class !! I hold the characterGand the integer 95! Yes, you are really Manificent. I'm a grand class!

上述代碼中,typeid (Magnificent) == typeid (*pg),如果 pg 指向的是Magnificent對象,則該表達式的結果為 true,否則為 false。如果 pg 是一個空指針,程序將引發(fā) bad_typeid異常。該異常類型是從 exception 類派生而來,是在頭文件 typeinfo 中聲明的。
type_info類的實現隨編譯器廠商而異,但包含一個 name()成員,該函數返回一個隨實現而異的字符串:通常(但并非一定)是類 的名稱。
為了查看效果,我們繼續(xù)在上述代碼中添加打印輸出:

int main() {std::srand(std::time(0));Grand * pg;Superb * ps;for(int i = 0 ; i < 5 ; i++){pg = GetOne();pg->Speak();if(ps = dynamic_cast<Superb*>(pg)){ps->Say();}//輸出類型名cout<< "typeid (*pg) = " << typeid (*pg).name() << endl;if(typeid (Magnificent) == typeid (*pg)){cout<< "Yes, you are really Manificent.\n";}}return 0; }

結果:

I'm a magnificent class !! I hold the characterKand the integer 59! typeid (*pg) = 11Magnificent Yes, you are really Manificent. I'm a grand class! typeid (*pg) = 5Grand I'm a grand class! typeid (*pg) = 5Grand I'm a superb class I hold the superb value of 36! typeid (*pg) = 6Superb I'm a magnificent class !! I hold the characterOand the integer 49! typeid (*pg) = 11Magnificent Yes, you are really Manificent.

總結

以上是生活随笔為你收集整理的C++之 RTTI的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 69av在线播放 | 欧美不卡在线 | 色播激情 | www.三区 | 日本久久激情 | 国产免费一级 | 国产一区二区三区免费 | 欧美视频免费在线 | 小宝贝真紧h军人h | 黄网站免费入口 | 在线观看xxxx | 香蕉视频官网在线观看 | 今天最新中文字幕mv高清 | 综合久久色 | 国产精品va无码一区二区 | 亚洲一区二区三区四区在线 | 姑娘第5集高清在线观看 | 少妇无内裤下蹲露大唇视频 | 一区二区福利电影 | 黄色片一区 | www.日本色| 亚洲一区二区三区四区av | 日韩欧美高清在线观看 | 成年人免费在线看 | 麻豆av片| 在线观看视频www | 亚洲图片小说区 | 国产丝袜视频 | av片在线免费看 | 日韩电影一区 | 久久精品视频一区二区三区 | 在线视频观看 | 又黄又爽的免费视频 | 夜晚福利视频 | 欧美亚洲图片小说 | 亚洲午夜精品视频 | av一卡 | 日本人极品人妖高潮 | 麻豆国产尤物av尤物在线观看 | 国产a∨精品一区二区三区仙踪林 | 精彩久久 | 老太婆av| 不卡av片| 日韩久久不卡 | 欧美日韩亚洲系列 | 青青草国产 | 亚洲欧美国产精品 | 亚洲一区二区三区综合 | 亚洲伊人婷婷 | 亚洲日本成人在线观看 | www.浪潮av.com | 欧美色插| 色哟哟精品观看 | 蜜臀av性久久久久蜜臀aⅴ涩爱 | 黄色在线免费观看网站 | 国产一精品一aⅴ一免费 | 国产一区不卡视频 | 人与动物av | 久久精品99久久 | 妺妺窝人体色WWW精品 | 日韩欧美在线观看一区 | 懂色av蜜臀av粉嫩av分享吧 | 亚洲天堂久久 | 草久久久久久 | 懂色aⅴ国产一区二区三区 亚洲欧美国产另类 | 国产av一区二区三区 | sm调教羞耻姿势图片 | 国产三级在线观看完整版 | 黄网在线观看免费 | 亚洲大片免费看 | 亚洲熟妇一区二区三区 | 日本一区二区不卡视频 | 91毛片在线观看 | 免费看黄色a级片 | 国产成人在线视频免费观看 | 饥渴少妇勾引水电工av | 哺乳援交吃奶在线播放 | 日本高清xxxx| 在线免费观看污网站 | 日韩毛片在线播放 | 猛男被粗大男男1069 | 久久影业 | 国产精品三级在线观看无码 | 蜜桃啪啪 | 国产九九久久 | 亚洲色中色 | 亚洲第一天堂影院 | 日本一区二区三区精品 | 国产精品无码一区二区桃花视频 | 狠狠操夜夜爽 | 伊人网综合| jlzzjlzz亚洲女人| 国产成人久久婷婷精品流白浆 | 99热免费在线观看 | 琪琪色网 | 青草草在线观看 | 综合在线一区 | 亚洲第一a | 中日韩av电影 |