国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C/C++ - C++ typeid 和虛函數詳解

C++ typeid 和虛函數詳解

2021-12-31 15:12chls C/C++

這篇文章主要介紹了c++ typeid 和虛函數的使用,幫助大家更好的理解和使用c++,感興趣的朋友可以了解下,希望能夠給你帶來幫助

typeid 和虛函數

前面咱們講到 typeid 的操作返回值是 type_info 對象的引用,然后輸出返回值的地址是相同的,測試代碼如下:

#include <iostream>
#include <functional>
using namespace std;
class Base{
public:
  virtual 
	void test(){
		cout << "Base::test" << endl;
	}
};
class Derived : public Base{
public:
  void test(){
		cout << "Derived::test" << endl;
	}
	virtual 
	~Derived(){
		cout << "Derived::~Derived" << endl;
	}
};
int main()
{
	Base* pBase = new Base();
	Base* pBase2 = new Derived();
	Derived* pDerive = new Derived();
	//typeid(pBase2) 和 typeid(pDerive) 返回地址相同
  cout << "typeid(pBase2) = " << &typeid(*pBase2) <<  " typeid(pDerive) = "<< &typeid(*pDerive) << endl;
  return 0;
}

output信息:

typeid(pBase2) = 0x55dd724c6d48 typeid(pDerive) = 0x55dd724c6d48

也就是說,0x55dd724c6d48 就是 Derived 類編譯之后的類標識(type_info)數據信息!是否真的如此,咱們可以添加一下代碼測試:

int main()
{
	Base* pBase = new Base();
	Base* pBase2 = new Derived();
	Derived* pDerive = new Derived();
	//typeid(pBase2) 和 typeid(pDerive) 返回地址相同
  cout << "typeid(pBase2) = " << &typeid(*pBase2) <<  " typeid(pDerive) = "<< &typeid(*pDerive) << endl;
	//class Base type_info 地址
	cout << "typeid(Base) = " << &typeid(Base)  << endl;
	//class Derive type_info 地址
	cout << "typeid(Derived) = " << &typeid(Derived)  << endl;
  //指針類型推導
  cout << "point ---- typeid(pBase2) = " << &typeid(pBase2) <<  " typeid(pDerive) = "<< &typeid(pDerive) << endl;
  return 0;
}

ouput信息:

typeid(pBase2) = 0x562309345d48 typeid(pDerive) = 0x562309345d48
typeid(Base) = 0x562309345d60
typeid(Derived) = 0x562309345d48
point ---- typeid(pBase2) = 0x562309345d28 typeid(pDerive) = 0x562309345d08

可以看到,Derived 類的 type_info 信息的地址就是 0x558a4dec7d48 !要注意的一點:直接對指針類型進行操作,并不能返回正確的原始類型。

好了嘛,那 typeid 到底是咋從虛函數表找到這個地址的呢?如果大家看過我之前的 深入理解new[]和delete[]_master-計算機科學專欄-CSDN博客 一文,應該就能夠想到是不是C++編譯器對虛函數表進行構造的過程中是不是也一樣,做了地址偏移呢?

咱們看看上面代碼的匯編信息:

C++ typeid 和虛函數詳解

通過查看匯編信息,我們得到以下結論:

虛函數表中確實存有typeinfo信息(第一個虛函數的地址偏移 -1 即是)typeinfo信息是區分指針類型是的(指針類型有前綴P,例如 P4Base、P7Derived)

然后,我們仔細觀察四個 typeinfo 類(Derived*、 Base*、Derived、Base),每個typeinfo 類都有一個虛函數表,繼承自 vtable for __cxxabiv1::******* ,后面的信息會不一樣。這里對該信息做一下簡單說明:

對于啟用了 RTTI 的類來說會繼承 __cxxabiv1 里的某個類所有的基礎類(沒有父類的類)都繼承于_class_type_info所有的基礎類指針都繼承自 __pointer_type_info所有的單一繼承類都繼承自 __si_class_type_info所有的多繼承類都繼承自 __vmi_class_type_info

以typeinfo for Derived為例:

C++ typeid 和虛函數詳解

然后是指向存儲類型名字的指針,
如果有繼承關系,則最后是指向父類的 typeinfo 的記錄。

所以,如果是正常調 typeinfo 基類(_class_type_info、__pointer_type_info、__si_class_type_info、__vmi_class_type_info)的方法,應該會動態調到 type_info 的繼承類 (typeinfo for Derived*、typeinfo for Base*、typeinfo for Derived、typeinfo for Base)的方法。

但是,typeid 操作指針類型時并不是這樣,說明C++編譯器底層有特殊處理!

調試以下代碼:

  cout << typeid(*pBase2).name();
  cout << typeid(*pDerive).name();
  cout << typeid(pBase2).name();
  cout << typeid(pDerive).name();

通過匯編信息,可以看到這里并沒有做任何動態調用的邏輯,而是直接返回該指針類型的typeinfo信息,這也就解釋了為什么 typeid 操作指針和操作對象的結果不一樣!

C++ typeid 和虛函數詳解

那么我們在使用typeid時,如果要獲取到真實對象類型,應該要將指針去掉!

為了驗證我們前面的結論: 虛函數表中確實存有typeinfo信息(第一個虛函數的地址偏移 -1 即是),咱們可以直接通過指針的方式操作虛函數表!

測試代碼如下:

#include <iostream>
#include <functional>
using namespace std;
class Base{
public:
  virtual 
	void test(){
		cout << "Base::test" << endl;
	}
};
class Derived : public Base{
public:
  void test(){
		cout << "Derived::test" << endl;
	}
	virtual 
	~Derived(){
		cout << "Derived::~Derived" << endl;
	}
};
typedef void (*FUNPTR)();
type_info* getTypeInfo(unsigned long ** vtbl){
	type_info* typeinfo = (type_info*)((unsigned long)vtbl[-1]);
	return typeinfo;
}
void visitVtbl(unsigned long ** vtbl, int count)
{
  cout << vtbl << endl;
  cout << "\t[-1]: " << (unsigned long)vtbl[-1] << endl;
  typedef void (*FUNPTR)();
  for (int i = 0; vtbl[i] && i < count; ++i)
  {
      cout << "\t[" << i << "]: " << vtbl[i] << " -> ";
      FUNPTR func = (FUNPTR)vtbl[i];
      func();
  }
}
int main()
{
	Base* pBase = new Base();
	Base* pBase2 = new Derived();
	Derived* pDerive = new Derived();
	//這里去遍歷虛函數表
	visitVtbl((unsigned long **)*(unsigned long **)pBase2, 2);
	//獲取虛函數表-1位置的typeinfo地址
	cout << "pDerive = " << getTypeInfo((unsigned long **)*(unsigned long **)pDerive) << " "
	<< getTypeInfo((unsigned long **)*(unsigned long **)pDerive)->name() << endl;
	//獲取虛函數表-1位置的typeinfo地址
	cout << "pBase2 = " << getTypeInfo((unsigned long **)*(unsigned long **)pBase2) << " "
	<< getTypeInfo((unsigned long **)*(unsigned long **)pBase2)->name() << endl;
  return 0;
}

這里要注意的一點是,遍歷虛函數表 visitVtbl 方法的第2個參數,自己控制不要越界,此外,還要注意調用的順序,如果先調用了虛析構函數,會導致內存錯誤!

output信息:

0x5620022edd10
[-1]: 94695475567936
[0]: 0x5620022eb5fa -> Derived::test
[1]: 0x5620022eb636 -> Derived::~Derived
pDerive = 0x5620022edd40 7Derived
pBase2 = 0x5620022edd40 7Derived

通過直接訪問虛函數表-1位置,我們可以看到輸出的日志信息與我們前面的結論是一致的!也即是C++編譯器給我們做了偏移操作(在-1的位置存儲了type_info信息,實例化對象中的虛函數表地址是偏移之后的地址)。

 

總結

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注服務器之家的更多內容!

原文鏈接:https://blog.csdn.net/zhaxun/article/details/120166140

延伸 · 閱讀

精彩推薦
  • C/C++c++ 單線程實現同時監聽多個端口

    c++ 單線程實現同時監聽多個端口

    這篇文章主要介紹了c++ 單線程實現同時監聽多個端口的方法,幫助大家更好的理解和學習使用c++,感興趣的朋友可以了解下...

    源之緣11542021-10-27
  • C/C++C/C++經典實例之模擬計算器示例代碼

    C/C++經典實例之模擬計算器示例代碼

    最近在看到的一個需求,本以為比較簡單,但花了不少時間,所以下面這篇文章主要給大家介紹了關于C/C++經典實例之模擬計算器的相關資料,文中通過示...

    jia150610152021-06-07
  • C/C++學習C++編程的必備軟件

    學習C++編程的必備軟件

    本文給大家分享的是作者在學習使用C++進行編程的時候所用到的一些常用的軟件,這里推薦給大家...

    謝恩銘10102021-05-08
  • C/C++C語言實現電腦關機程序

    C語言實現電腦關機程序

    這篇文章主要為大家詳細介紹了C語言實現電腦關機程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    xiaocaidayong8482021-08-20
  • C/C++詳解c語言中的 strcpy和strncpy字符串函數使用

    詳解c語言中的 strcpy和strncpy字符串函數使用

    strcpy 和strcnpy函數是字符串復制函數。接下來通過本文給大家介紹c語言中的strcpy和strncpy字符串函數使用,感興趣的朋友跟隨小編要求看看吧...

    spring-go5642021-07-02
  • C/C++深入理解goto語句的替代實現方式分析

    深入理解goto語句的替代實現方式分析

    本篇文章是對goto語句的替代實現方式進行了詳細的分析介紹,需要的朋友參考下...

    C語言教程網7342020-12-03
  • C/C++C++之重載 重定義與重寫用法詳解

    C++之重載 重定義與重寫用法詳解

    這篇文章主要介紹了C++之重載 重定義與重寫用法詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下...

    青山的青6062022-01-04
  • C/C++C語言中炫酷的文件操作實例詳解

    C語言中炫酷的文件操作實例詳解

    內存中的數據都是暫時的,當程序結束時,它們都將丟失,為了永久性的保存大量的數據,C語言提供了對文件的操作,這篇文章主要給大家介紹了關于C語言中文件...

    針眼_6702022-01-24
主站蜘蛛池模板: 依人在线 | 日韩av电影在线观看 | 国产综合一区二区 | 亚洲国产精品99久久久久久久久 | 国产视频色 | 黄免费| 久久97视频 | 久久久人成影片一区二区三区 | 日韩视频在线播放 | 欧美一二 | 日韩中文在线 | 欧美日在线 | 日韩av色 | 一区二区乱码 | 天天干人人 | 日韩欧美一区二区三区 | 亚洲欧美日韩另类精品一区二区三区 | 免费看黄色一级电影 | 日韩在线免费观看视频 | 狠狠操狠狠操 | 中文字幕在线免费 | 激情欧美日韩一区二区 | 在线色综合 | 97成人在线免费视频 | 国产视频久久 | 精品久久久久久久人人人人传媒 | 日本少妇一区二区三区 | 东南亚一级毛片 | 国产精品成人3p一区二区三区 | 能直接看的av网站 | 欧美日韩成人网 | 久久久国产视频 | 成人精品一区二区 | 欧美日韩国产一区二区三区 | 中文字幕第18页 | 日本精品免费 | 在线看国产 | 动漫羞免费网站中文字幕 | 91在线影视 | 精品成人av | 亚洲午夜av |