定义派生类和继承类(从汇编分析)
下面我來分析幾段繼承的類跟大家總結一下前面所說的一些理論知識,這里解釋了前面 提供默認構造函數的第二點哦,仔細看
仔細觀察地址401090,這里先調用了子類的構造函數,但是原來子類里面并沒有構造函數,這就是編譯器給出的默認構造函數,需要通過這個構造函數,像一個踏板一樣,跳到父類的構造函數去,這里就是前面所講過的 提供默認構造函數的第二點知識。(情況是:父類有構造函數,但是子類沒有)
(這里我一直在想,不是得先調用父類的構造函數嗎,為什么這里先子類呢?因為你要發(fā)現是否有父類,你得先進入子類構造函數去看,先進子類構造函數去看,如果有,則跳到父類構造函數,沒有則向下執(zhí)行,因為這里是提供的默認構造函數,即空函數,所以的話,只有進門操作,執(zhí)行操作的話直接沒了,所以直接返回)
總結:
當CDervie類沒有構造函數時,為了能夠在CDervie類對象 產生時調用 成員對象 的構造函數,編譯器同樣會提供默認構造函數,以實現成員構造函數的調用。
但是,如果子類含有構造函數,而父類不存在構造函數,則編譯器不會為父類提供默認的構造函數。在構造子類時,由于父類中沒有虛表指針,也不存在構造祖先類的問題,因此添加默認構造函數沒有任何意義。
匯編角度來看待構造順序
根據上面匯編代碼分析:
構造的順序為:先構造父類(地址4010D5處),然后按聲明的順序構造成員對象(地址4010E7處)和初始化列表中的指定的成員(地址4010EF處),最后才是構造函數(地址4010F6處)。
有了這樣的內存結構,不但可以使用指向子類對象的子類指針間接尋址到父類定義的成員,而且可以使用指向子類對象的父類指針間接尋址到父類定義的成員中。
在使用父類成員函數中,傳遞的this指針也可以是子類對象的首地址,因此,在父類中,可以根據以上內存結構將子類對象的首地址視為父類對象的首地址來進行數據操作,而且還不會出錯。
由于父類對象的長度不超過子類對象,而子類對象只要派生新的數據,其長度即可超過父類,因此子類指針的尋址范圍不小于父類指針,在使用子類指針訪問父類時,如果訪問的成員數據是父類對象所定義的,那么不會出錯,如果訪問的是子類派生的成員數據,則會造成訪問越界。
父類中成員函數SetNumber 在子類中并沒有被定義,但根據派生關系,子類中可以使用父類的共有函數。編譯器是如何實現正確匹配呢?
如使用對象或對象的指針調用成員函數,編譯器可根據對象所屬作用域來使用“名稱粉碎法”,以實現正確匹配。在成員函數中調用其他成員函數時,可匹配當前作用域。
父類數據成員被排列在最前端的目的是為了在添加派生類后方便子類使用父類中的成員類型,并且可以將子類指針當父類指針來使用。
這樣一來,不管是操作子類對象還是父類對象,只要確認了對象的首地址,對父類成員數據的偏移量而言都是一樣的。對子類的對象而言,使用父類指針或者子類指針都可以正確訪問其父類數據。反之,如果使用一個子類對象的指針去訪問父類對象,則存在越界訪問的危險。
子類對象的指針訪問父類對象存在的危險:
總結
以上是生活随笔為你收集整理的定义派生类和继承类(从汇编分析)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2020-12-18(何种情况下编译器会
- 下一篇: 析构设置为虚函数的原因