網站首頁 編程語言 正文
指針
我們在書本上學到的指針基本上都是:首先,指針是一個變量;其次,這個變量存儲的值是一個地址。這個是對指針的一個基本理解,最近在編程中發現了一些新的東西。
首先,指針不僅僅是一個地址,還存在一個和所指向內容大小相關的值,如下代碼:
#include<iostream> using namespace std; int main() { int a = 10; int *pa = &a; cout << "pa: " << pa << endl; cout << "pa+1: " << pa + 1 << endl; short b = 1; short *pb = &b; cout << "pb: " << pb << endl; cout << "pb+1: " << pb + 1 << endl; void *ppa = &a; cout << "ppa:" << ppa << endl; cout << "ppa+1: " << ppa + 1 << endl; return 0; }
從運行結果可以看出pa+1,地址增加了4個字節;pb+1,地址增加了2個字節;ppa+1,地址增加了2個字節;而使用void指針指向整型變量a,此時ppa+1,地址只增加了1個自己。從這個結果我們可以很明顯看出,指針不僅僅是一個存地址的變量,還存在一個和內存分配相關的值。其實進一步說,指針不僅僅是一個地址值,還存放著如何解釋內存的規則。(void指針只存放地址,沒有解釋規則)
指針和繼承
眾所周知,繼承可以實現用父類的指針來指向子類的對象,為什么可以這樣用呢?正如上面所說,指針保存地址和解釋內存的規則,當你聲明一個父類指針,那么你就指明了該指針的解釋規則,當你將子類地址傳給指針時,你就相當于給了一塊內存給這個指針,然后這個指針就可以用它的規則去解釋這塊內存。根據上面的說法,那么我們可以得出,子類對象中必定存在一塊內存,其分配方式和父類對象一模一樣(如果把這塊內存單獨提取出來,它就是一個父類對象),事實也是如此,而且這塊“父類對象”一般都是存放在子類對象的最前面,這就解釋了子類在構造的時候,一定會先調用父類構造函數。同時,“父類對象”指針只能訪問自己的父類成員。那么考慮多繼承的情況,多繼承的子類,其內存空間中必定存在多個“父類對象”空間,這些父類空間的地址必定是不同的,那么就會造成同一個多繼承的子類,用其不同的父類指針指向它,其地址值是不同的,實際測試的確如此:
#include<iostream> using namespace std; class A { public: int a = 10; long int aa = 100; }; class B { public: int b = 20; }; class C : public A, public B { public: int c = 30; }; int main() { C c; A *pA; B *pB; C *pC; pA = &c; pB = &c; pC = &c; cout << "pA: " << pA << endl; cout << "pB: " << pB << endl; cout << "pC: " << pC << endl; cout << "pA.a: " << &(pA->a) << endl; cout << "pA.aa: " << &(pA->aa) << endl; cout << "pB.b: " << &(pB->b) << endl; cout << "pC.c: " << &(pC->c) << endl; return 0; }
其內存布局如圖,pA、pB都指向各自的“父類對象”空間起始位置,pA只能訪問a、aa,pB只能訪問b(至于為什么a是int卻占8個字節,這個和內存對齊有關,自行查詢)。
指針、繼承和多態
C++的繼承和多態繞不過的一個東西便是虛指針和虛函數,這里簡單說一下:首先,在含有虛函數的類中,會產生一個虛函數表,注意這個虛函數表是從屬于類的,不是從屬于對象,也就是多個對象共享這個虛函數表。其次,每個類聲明的對象都會有一個虛指針,這個虛指針指向類的虛函數表。(這里只是簡單提及一下,更多的東西可以自行查詢)看過很多網上的東西,都說虛指針是每個對象的第一個數據成員,也就是分配在最開頭的地址空間。其實,我覺得這句話不完全正確,因為當多繼承中有虛函數時,虛函數表就有多個,虛指針也有多個,這些虛指針不一定全都存在于最開始的地址空間。應該說,這些虛指針存在于繼承的父類所管理區域的開頭:
#include<iostream> using namespace std; class A { public: int a = 10; long int aa = 10; virtual void f() { } }; class B { public: int b = 20; virtual void g() { } }; class C : public A, public B { public: int c = 30; virtual void cc() { } }; int main() { A *pA; B *pB; C c; pA = &c; pB = &c; cout << pA << endl; cout << &(pA->a) << endl; cout << &(pA->aa) << endl; cout << pB << endl; cout << &(pB->b) << endl; cout << &(c.c) << endl; return 0; }
從上面的結果可以看出,虛指針不一定都是存在最開始的位置,如果硬要說是開始,應該也是相對于“父類對象”區域的開始。
原文鏈接:https://blog.csdn.net/m0_37271605/article/details/122346640
相關推薦
- 2023-01-23 python操作excel之xlwt與xlrd_python
- 2022-10-15 Go?Excelize?API源碼閱讀GetPageLayout及SetPageMargins_Go
- 2022-02-14 記關于Android開發中使用System.currentTimeMillis()不準確的問題
- 2023-01-13 BatchNorm2d原理、作用及pytorch中BatchNorm2d函數的參數使用_python
- 2023-03-23 React?Native中WebView與html雙向通信遇到的坑_React
- 2022-07-18 SpringBoot之定時任務三種實現方法
- 2022-09-04 Python?Matplotlib繪制箱線圖boxplot()函數詳解_python
- 2022-08-20 C/C++多態深入探究原理_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支