每日一問(11) 什麼是虛函數

2021-02-21 程序猿思維
故事

這是餐桌上一個必點菜,大家都知道,根本不是獨家秘笈,但是看了無數次文章和book,依然完全被錘,停留 表面上,完全不知道對方在想什麼,

其實很簡單,就這樣呀。

感覺沒問題就是最大的問題。

無論任何公司阿里,滴滴,還有騰訊,還是普通公司

都上這個菜,這就是一條線索,故事的線索。

別人都知道,我不知道 才是最尷尬的地方



C++通過指針實現了多態,運行時函數重載決議,

是他最有優秀地方,但是也是最讓人痛苦地方,

內存模型假設存在讓對象生命周期管理更加複雜。異常總是在看不到地方出現。怎麼辦?

然後出現了智能指針,這能說拆東牆補西牆嗎?

為了保證正確拷貝賦值,

虛指針和智能指針在類型轉換 採取哪些措施保證唯一或者正確 ,

這可能是隱藏的副本,boss任務。


我需要你必須重視起來,思想上重視就是口號,必須採取行動必須閱讀

RocksDB是使用C++編寫的嵌入式kv存儲引擎 和

看到別人是怎麼用的,從這裡開始,

簡述C++虛函數作用及底層實現原理(牛客)


思考:複製操作和虛函數有關係嗎?


問題1:什麼複製拷貝

問題2:默認拷貝對虛函數做了什麼

從彙編看c++中臨時對象的析構時機

參考 https://blog.csdn.net/chaoguo1234/article/details/81277613

問:系統自動合成的default copy assignment operator對虛函數有什麼操作?

A class does not exhibit bitwise copy semantics for the default copy assignment operator:

When the class declares one or more virtual functions (we must not copy the vptr address of the right- hand class object, since it might be a derived class object)

問題3:什麼是move copy

標準庫:如何使用

疑問:既然虛函數表,在編譯時候確定了,並且放到只讀數據段,問題來了,如果繼承重寫需要修改裡面函數地址給怎辦?並且不同對象 this不一樣,虛函數表 只讀數據段 怎麼確定 每個對象函數運行地址怎麼共用呀?這不是自相矛盾?

https://maimai.cn/web/gossip_detail?gid=28548835&egid=f9572a925d4d11ebbb08801844e2d86c

使用gdb探索 C++ 虛函數表

不同對象,創建不同的虛指針嗎?創建不同的虛函數表嗎?,


一個類可以創建多個對象 在創建對象時,編譯系統只為對象中的成員數據(成員變量)分配內存空間 而同類對象的成員函數的代碼卻是共享的。

內部的成員函數:普通函數:不佔用內存。虛函數:要佔用4個字節,用來指定虛函數的虛擬函數表的入口地址。所以一個類的虛函數所佔用的地址是不變的.

set print object on(gdb) n39      Derived d; (gdb) n40      Derived d1;  (gdb) p d$1 = (Derived) {<Base> = {    _vptr.Base = 0x555555755d48 <vtable for Derived+16>}, <No data fields>}(gdb) p d1$2 = (Derived) {<Base> = {    _vptr.Base = 0x555555755d48 <vtable for Derived+16>}, <No data fields>}(gdb) 
(gdb) p /a *((void**)0x555555755d48)(gdb) shel c++filt _ZTI7Derivedtypeinfo for Derived


虛函數的間接調用

只有對於通過指針或引用的方式調用虛函數才是間接調用

普通方法的調用是直接將地址寫在調用位置的,稱作直接調用

那在有了virtual關鍵字之後再通過指針或引用調用 時,編譯器在編譯時肯定不會直接寫,因為它需要查表才能知道要調用哪個方法,所以稱作間接調用 ,需要注意,只有通過指針或引用來調用才會發生間接調用

從彙編角度分析g++編譯器如何實現虛函數動態綁定


g++ -S -g  class_virtaul_fuc.cpp call _ZN6ClassBC1Evcall *%rdx

相關焦點

  • C++虛函數詳解
    下面,我將分別說明「無覆蓋」和「有覆蓋」時的虛函數表的樣子。沒有覆蓋父類的虛函數是毫無意義的。 我們可以看見,三個父類虛函數表中的f()的位置被替換成了子類的函數指針。這樣,我們就可以任一靜態類型的父類來指向子類,並調用子類的f()了。
  • C++中的虛函數重載
    1 overload:指的是相同作用域中的兩個函數的函數名相同,但參數列表的個數、順序、類型不同。而override指的是子類中重新定義的父類的虛函數;2 override:overload要求兩個函數的參數列表必須不同,但是不要求這兩個函數必須是虛函數。而override要求必須是虛函數且父類的虛函數必須有virtual關鍵字,函數的參數列表和返回值也必須相同。
  • C++虛函數表剖析
    關鍵詞:虛函數,虛表,虛表指針,動態綁定,多態一、概述為了實現C++的多態,C++使用了一種動態綁定的技術
  • C++ | 虛函數簡介
    內存布局 如果一個類有虛函數,編譯器會自動為這個類型的對象在頭部增加一個虛表指針(vftable),指向虛函數表。虛函數表中存放著一個個的虛函數。CBase 和 CDerived 類對象的內存布局如下:
  • C++中的虛函數(virtual function)
    bar(){ A a; a.foo(); // A::foo()被調用}1.1 多態 在了解了虛函數的意思之後,再考慮什麼是多態就很容易了。再回頭看看1.1中的例子,bar()作為A-B這個類層次的使用者,它並不知道這個類層次中有多少個類,每個類都叫什麼,但是一樣可以很好的工作,當有一個C類從A類派生出來後,bar()也不需要「知道」(修改)。這完全歸功於多態--編譯器針對虛函數產生了可以在運行時刻確定被調用函數的代碼。
  • c++ 內存,虛函數,運算函數,三角函數
    :就是java中的抽象,純虛函數只有聲明沒有具體實現就是空方法,在子類中必須重新寫,虛函數就是在基類中寫了有實現。他們都得用關鍵字 virtual(虛擬的) 聲明的函數1. 虛函數和純虛函數可以定義在同一個類(class)中,含有純虛函數的類被稱為抽象類(abstract class),而只含有虛函數的類(class)不能被稱為抽象類(abstract class)。2.
  • C++語言虛函數實現多態的原理
    在C++的標準規格說明書中說到,編譯器必需要保證虛函數表的指針存在於對象中最前面的位置(這是為了保證正確取到虛函數的偏移量)。這意味著我們通過對象實例的地址得到這張虛函數表,然後就可以遍歷其中函數指針,並調用相應的函數。
  • C++ 虛函數表及多態內部原理詳解
    2、 虛表可以繼承,如果子類沒有重寫虛函數,那么子類虛表中仍然會有該函數的地址,只不過這個地址指向的是基類的虛函數實現。如果基類3個虛函數,那麼基類的虛表中就有三項(虛函數地址),派生類也會有虛表,至少有三項,如果重寫了相應的虛函數,那麼虛表中的地址就會改變,指向自身的虛函數實現。如果派生類有自己的虛函數,那麼虛表中就會添加該項。
  • 面試必知必會|理解C++虛函數
    靜態綁定和動態綁定要充分理解多態,就要先說什麼是綁定?綁定體現了函數調用和函數本身代碼的關聯,也就是產生調用時如何找到提供調用的方法入口,這裡又引申出兩個概念:在C++泛型編程中可以基於模板template和重載override兩種形式來實現靜態多態。
  • C++中虛函數和純虛函數的區別與總結
    定義他為虛函數是為了允許用基類的指針來調用子類的這個函數。定義一個函數為純虛函數,才代表函數沒有被實現。定義純虛函數是為了實現一個接口,起到一個規範的作用,規範繼承這個類的程式設計師必須實現這個函數。    return 0;  } 這個例子是虛函數的一個典型應用,通過這個例子,也許你就對虛函數有了一些概念。它虛就虛在所謂「推遲聯編」或者「動態聯編」上,一個類函數的調用並不是在編譯時刻被確定的,而是在運行時刻被確定的。由於編寫代碼的時候並不能確定被調用的是基類的函數還是哪個派生類的函數,所以被成為「虛」函數。
  • 衝擊中考數學滿分每日一題(11)
    昨天每日一題答案1.如圖1,在Rt△ABC中,∠C=90°,AC=2BC,點E從A點出發,沿折線AB﹣BC運動,到點C停止,點E在AB上以10、2019中考熱點問題胡不歸與二次函數11、一組二次函數與阿氏圓試題(一)12、一組二次函數與阿氏圓試題
  • golang每日一題(init函數和main函數)
    /go/src/go-main/app/app-svr/app-show/interface/conf/conf.go:279 +0x94大意是重複定義了一個配置,不過轉到報錯的地方發現並沒有任何地方引用這個方法,不知道什麼時候兩個包同時引用到這裡導致的重複定義
  • C++語言中的「虛函數」就像C語言中的指針,必須要弄懂的
    上一節較為詳細的討論了C++語言中基類被派生類繼承過程中的內存模型,尤其較為詳細的分析了虛函數及其虛表、虛表指針在內存中是如何分布,如何存儲的,這對於理解C++語言中的「動態綁定」是極有幫助的。理解C++語言中的「動態綁定」正如之前兩篇文章所討論的,C++語言中虛函數的「動態綁定」能為多態的實現帶來極大的便利——「動態綁定」機制是在程序運行時根據指針所指向對象的類型(而不是指針本身類型
  • 每日一題:Excel基礎函數之-COUNTIFS的用法!
    COUNTIFS是Office2013開始有的一個多條件計數函數,有了這個函數,做條件計數真是太方便了。
  • 2019高考數學每日一練1004,已知函數是奇函數,求參數的值
    2019高考數學每日一練1004,已知函數是奇函數,求參數的值。已知函數的奇偶性求參數的值這種題型通用的解法是:若函數是奇函數,則f(-x)=-f(x)恆成立,即可求出參數的值;若函數是偶函數,則f(-x)=f(x)恆成立,亦可求出參數的值。
  • c++虛繼承,多繼承
    ,虛表深度剖析例1: 以下代碼輸出什麼?最後附上內存結構圖:例2: 為什麼虛函數效率低?因為虛函數需要一次間接的尋址,而普通的函數可以在編譯時定位到函數的地址,虛函數是要根據虛指針定位到函數的地址。虛繼承什麼是虛繼承?它與一般的繼承有什麼不同?它有什麼用?虛擬繼承是多重繼承中特有的概念。虛擬基類是為解決多重繼承而出現的。請看下圖:
  • 2019高考數學每日一練1006,已知抽象函數為奇函數,求函數值
    2019高考數學每日一練1006,已知抽象函數為奇函數,求函數值。抽象函數沒有具體的表達式,無法利用函數性質和圖像來解決問題,全靠觀察能力和分析能力,特別是求值題,需要通過一系列合適的代值運算才能得到結果,該代哪些值以及對題中等式的變形應用是難點,高考常藉助這樣的題型來考查學生分析抽象問題的能力。
  • 2019高考數學每日一練1008,分段函數和二次函數,已知值域求參數
    2019高考數學每日一練1008,分段函數和二次函數,已知值域求參數。分段函數和二次函數均是歷屆高考數學重點考察的知識點,難度適中;對於本題,考察的主要內容有:分段函數值域的確定方法,二次函數在某區間上最值的確定方法,給出分段函數的值域求參數,等等;這樣的題型綜合的知識都是函數部分的重點,高考考察的可能性非常大,所以大家一定要重視。本題屬於通用題目,適合高中各年級段的學生練習,自己動手試著做一遍,然後再看後面的解析。
  • 每日一Excel技巧:日期函數,你都會嗎?
    每日一Excel技巧:日期函數,你都會用嗎?在Excel統計數據、分析數據中,日期函數是非常重要的一類函數,整理一下分享給大家。
  • 氣血虛肝火旺有什麼症狀、吃什麼藥?氣血虛肝火旺如何調理?
    氣血虛肝火旺吃什麼藥1、氣血虛肝火旺吃什麼藥呢對於普通人所引起的肝火旺,中醫常用夏枯草、桑葉、菊花或金銀花、綿茵陳調治來治療肝火旺。另外肝火旺時一般吃一些清淡的食物,再配合藥物治療就可以了,使用方法如下:將15克金銀花、15克綿茵陳加入適量的水浸泡半小時後煮半小時,即可代茶飲。可用黑糖或片糖或蜂蜜調味。