虛函數不能定義爲內聯函數

在C++中,inline關鍵字和virtual關鍵字分別用來定義c++中的內聯函數和虛函數,他們在各自的場合都有其各自的應用,下面將簡單介紹他們各自的功能,然後在說明為什麼一個函數不能同時是虛函數和內聯函數(inline)

  • 內聯函數(inline)

內聯函數的目的是為了減少函數調用時間。它是把內聯函數的函數體在編譯器預處理的時候替換到函數調用處,這樣代碼運行到這裡時候就不需要花時間去調用函數。但內聯函數有個缺點是它會增加執行文件大小。所以如果不適當的使用內聯函數會造成執行文件特別大。

而使用內聯函數有以下幾點需要注意:

  1. 頭文件中不僅要包含inline函數的聲明,還要包含inline函數的定義
  • 編譯器需要把inline函數體替換到函數調用處,所以編譯器必須要知道inline函數的函數體是啥,所以要將inline函數的函數定義和函數聲明一起寫在頭文件中,便與編譯器查找替換。
  1. 可以在同一個項目的不同源文件內定義函數名相同,實現相同的inline函數
  • 同一個inline函數可以多處聲明和定義,但是必須要完全相同
  1. 定義在class聲明內的成員函數默認是inline函數
  • 虛函數(virtual)

虛函數是為了實現多態特性的。虛函數的調用只有在程序運行的時候才能知道到底調用的是哪個函數,其是有有如下幾點需要注意:

  1. 類的構造函數不能是虛函數
  • 構造函數是為了構造對象的,所以在調用構造函數時候必然知道是哪個對象調用了構造函數,所以構造函數不能為虛函數。
  1. 類的靜態成員函數是虛函數
  • 類的靜態成員函數是該類共用的,與該類的對象無關,靜態函數里沒有this指針,所以不能為虛函數。
  • 虛函數不能定義為內聯函數的原因

inline是在編譯器將函數類容替換到函數調用處,是靜態編譯的。而虛函數是動態調用的,在編譯器並不知道需要調用的是父類還是子類的虛函數,所以不能夠inline聲明展開,所以編譯器會忽略

  • 總結
  1. 使用inline關鍵字的函數可能會被編譯器忽略而不在調用處展開,如虛函數。
  2. 如果定義的inline函數過大,為了防止生成的obj文件太大,編譯器會忽略這裡的inline聲明
  3. inline是在編譯器將函數類容替換到函數調用處,是靜態編譯的。而虛函數是動態調用的,在編譯器並不知道需要調用的是父類還是子類的虛函數,所以不能夠inline聲明展開,所以編譯器會忽略
  4. 頭文件中不僅要包含inline函數的聲明,還要包含inline函數的定義
  • 編譯器需要把inline函數體替換到函數調用處,所以編譯器必須要知道inline函數的函數體是啥,所以要將inline函數的函數定義和函數聲明一起寫在頭文件中,便與編譯器查找替換。
  1. 可以在同一個項目的不同源文件內定義函數名相同,實現相同的inline函數
  • 同一個inline函數可以多處聲明和定義,但是必須要完全相同
  1. 定義在class聲明內的成員函數默認是inline函數
  2. 類的構造函數不能是虛函數
  • 構造函數是為了構造對象的,所以在調用構造函數時候必然知道是哪個對象調用了構造函數,所以構造函數不能為虛函數。
  1. 類的靜態成員函數不能是虛函數
  • 類的靜態成員函數是該類共用的,與該類的對象無關,靜態函數里沒有this指針,所以不能為虛函數。

虛函數是為了實現動態綁定,不能聲明為虛函數的有:

1、靜態成員函數; 2、類外的普通函數; 3、構造函數; 4、友元函數

此外,還有一些函數可以聲明為虛函數,但是沒有意義,但編譯器不會報錯,如:

1、賦值運算符的重載成員函數: 因為複製操作符的重載函數往往要求形參與類本身的類型一致才能實現函數功能,故形參類型往往是基類的類型,因此即使聲明為虛函數,也把虛函數當普通基類普通函數使用。

2、內聯函數:內聯函數目的是在代碼中直接展開(編譯期),而虛函數是為了繼承後能動態綁定執行自己的動作(動態綁定),因此本質是矛盾的,因此即使內聯函數聲明為虛函數,編譯器遇到這種情況是不會進行inline展開的,而是當作普通函數來處理。因此聲明瞭虛函數不能實現內斂的,即內斂函數可以聲明為虛函數,但是毫無了內聯的意義

虛函數不能定義為內聯函數


分享到:


相關文章: