Graphics Software面試準備
個人針對芯片公司的Graphics Software崗位的面試筆記,主要分為4部分:c++基礎,圖形學基礎,圖形API
c++基礎
此部分綜合了網(wǎng)絡上的c++面經(jīng)、筆記以及個人在面試中遇到的問題。
Part1:class相關
- 純虛函數(shù)可以有實現(xiàn)嗎?
答:語法層面來講可以有,但是一個類只要含有純虛函數(shù)就變成了抽象類,為純虛函數(shù)提供實現(xiàn)也無法實例化。純虛函數(shù)由繼承該類的子類實現(xiàn),子類可以實例化。 - 定義一個空類,有哪些默認的函數(shù)?
默認構造函數(shù)
默認拷貝構造函數(shù)
默認析構函數(shù)
默認重載賦值運算符函數(shù)
默認重載取址運算符函數(shù)
默認重載取址運算符const函數(shù)
默認移動構造函數(shù)(C++11)
默認重載移動賦值操作符函數(shù)(C++11)。 - 析構函數(shù)為什么要設置成虛函數(shù)?構造函數(shù)可以是虛函數(shù)嗎?
構造函數(shù)不能是虛函數(shù),編譯會報錯。每個對象的虛函數(shù)表是在構造函數(shù)中初始化的,因此構造函數(shù)不能是虛函數(shù)。析構函數(shù)一般都是虛函數(shù),當一個基類指針指派生類對象時,通過該指針調用對象時就可以調用到子類的析構函數(shù),從而釋放所有資源。 - 虛函數(shù)的實現(xiàn)原理?
虛函數(shù)通過虛函數(shù)表實現(xiàn),有以下幾個注意點:
1)虛函數(shù)表是編譯器在編譯時期為我們創(chuàng)建好的, 只存在一份。
2)定義類對象時, 編譯器自動將類對象的__vfptr指向這個虛函數(shù)表。 3)vfptr是指向函數(shù)指針數(shù)組的指針,const void**,指針指向的內容不可更改。
4)如果派生類實現(xiàn)了基類的某個虛函數(shù),則在虛表中覆蓋原本基類的那個虛函數(shù)指針,在編譯時根據(jù)類的聲明創(chuàng)建。 5)編譯器生成虛表-(指針數(shù)組)》開辟內存-》寫入虛表(吧虛表寫入到內存中)-》構造函數(shù)-》調用虛函數(shù)。 6)構造函數(shù)內部調用虛函數(shù),語法層面是允許的,但調用虛函數(shù)只能調用該類的虛函數(shù),無法實現(xiàn)多態(tài)。 - 內聯(lián)函數(shù)可以是虛函數(shù)嗎?
虛函數(shù)可以是內聯(lián)函數(shù),內聯(lián)是可以修飾虛函數(shù)的,但是當虛函數(shù)表現(xiàn)多態(tài)性的時候不能內聯(lián)。內聯(lián)是在編譯期建議編譯器內聯(lián),而虛函數(shù)的多態(tài)性在運行期,編譯器無法知道運行期調用哪個代碼,因此虛函數(shù)表現(xiàn)為多態(tài)性時(運行期)不可以內聯(lián)。 - 為什么類的成員模版函數(shù)不能是虛函數(shù)?
因為模板函數(shù)可以有無數(shù)個實例,所以編譯器在編譯時無法為其生成一個確定的虛函數(shù)表條目,無法確定需要調用哪個特定的模板實例。 - 隱藏是什么?
派生類的函數(shù)屏蔽了基類的同名函數(shù),只需要函數(shù)名字相同,無論參數(shù)列表是否相同,其基類函數(shù)都會被隱藏。 - 空類的大小是?
1字節(jié)。要求每個對象必須具有獨一無二的內存地址。 - 在成員函數(shù)中調用delete this會發(fā)生什么
在類對象的內存空間中,只有數(shù)據(jù)成員和虛函數(shù)表指針,并不包含代碼內容,類的成員函數(shù)單獨放在代碼段中。當調用delete this時,類對象的內存空間被釋放。在delete this之后進行的其他任何函數(shù)調用,只要不涉及到this指針的內容,都能夠正常運行。對象不可以使用。一旦涉及到this指針,如操作數(shù)據(jù)成員,調用虛函數(shù)等,就會出現(xiàn)不可預期的問題。 - 在類的析構函數(shù)中調用delete this會發(fā)生什么?
棧溢出。delete關鍵字會調用類的析構函數(shù),從而造成棧溢出。 - 為什么成員初始化列表會快一些?
對于類型,它少了一次調用構造函數(shù)的過程,而在函數(shù)體中賦值則會多一次調用。而對于內置數(shù)據(jù)類型則沒有差別。
Part2:語言基礎
-
引用的本質是什么?引用和指針的區(qū)別是什么?
可以將引用理解為一個對象的別名,引用在底層是通過指針實現(xiàn)的,const ptr*。引用在創(chuàng)建時必須被初始化,不能為NULL,在初始化之后不能進行更改。 -
volatile關鍵字
volatile 關鍵字聲明的變量,每次訪問時都必須從內存中取出值,告訴編譯器不應對這樣的對象進行優(yōu)化。const 可以是 volatile (如只讀的狀態(tài)寄存器)。 -
sizeof
數(shù)組作為參數(shù)傳入函數(shù)后會退化為指針,sizeof的結果是指針的大小。當數(shù)組直接作為 sizeof 的參數(shù)時,返回的是數(shù)組占據(jù)內存空間的大小。 -
c++字節(jié)序列
大端:高位字節(jié)在低地址,低位字節(jié)在高地址。
小端:低位低地址,高位高地址 -
左值和右值
左值是可以取地址的,而右值不可以。
右值引用和move語句結合使用可以避免拷貝。 -
引用折疊
T& & -> T&
T& && -> T&
T&& & -> T&
T&& && -> T&&
萬能引用
template <typename T>
void MyFunc(T&& value) {
}
-
c++內存模型
1)堆
2)棧
3)自由存儲區(qū) new/delete
4)常量存儲區(qū)
5)全局/靜態(tài)存儲區(qū) -
typedef vs #define
- 用法不同:typedef 用來定義一種數(shù)據(jù)類型的別名,增強程序的可讀性。define 主要用來定義 常量,以及書寫復雜使用頻繁的宏。
- 執(zhí)行時間不同:typedef 是編譯過程的一部分,有類型檢查的功能。define 是宏定義,是預編譯的部分,其發(fā)生在編譯之前,只是簡單的進行字符串的替換,不進行類型的檢查。
- 作用域不同:typedef 有作用域限定。define 不受作用域約束,只要是在define 聲明后的引用 都是正確的。
- 對指針的操作不同:typedef 和define 定義的指針時有很大的區(qū)別。
- 靜態(tài)鏈接庫和動態(tài)鏈接庫
- 在鏈接階段,會將匯編生成的目標文件.o與引用到的庫一起鏈接打包到可執(zhí)行文件中。因此對應的鏈接方式稱為靜態(tài)鏈接。
- 動態(tài)庫在程序編譯時并不會被連接到目標代碼中,而是在程序運行是才被載入。不同的應用程序如果調用相同的庫,那么在內存里只需要有一份該共享庫的實例,規(guī)避了空間浪費問題。
STL相關
-
std::vector
1)vector底層通過動態(tài)數(shù)組實現(xiàn),空間不夠時會進行擴容,將空間擴大為原來的1.5倍,將原有數(shù)據(jù)拷貝到新的空間中,釋放原來占據(jù)的空間。
2)reserve和resize:reserve只改變capacity,但是不改變size。resize(n)將size變?yōu)閚,若原有的capacity<n,則改變capacity。
3)迭代器:插入和刪除元素都可能導致迭代器失效(開辟新的空間,導致原地址失效)。使用迭代器刪除元素時,it = vec.erase(it);
-
紅黑樹和AVL樹
stl中的map和set都是基于紅黑樹實現(xiàn),每個節(jié)點是紅色或者黑色,根結點和葉子結點都是黑的,如果一個節(jié)點是紅色的,那么它的兩個子節(jié)點都是黑色的。
AVL樹是一棵二叉搜索樹,每個結點的左右子樹的高度之差的絕對值(平衡因子)最多為1。
AVL 樹比紅黑樹更加平衡,但AVL樹在插入和刪除的時候也會存在大量的旋轉操作。所以當你的應用涉及到頻繁的插入和刪除操作,切記放棄AVL樹,選擇性能更好的紅黑樹;當然,如果你的應用中涉及的插入和刪除操作并不頻繁,而是查找操作相對更頻繁,那么就優(yōu)先選擇 AVL 樹進行實現(xiàn)。
圖形學基礎
芯片公司的graphics software崗位要求對圖形學相關的基礎知識有一定了解。下面總結一些常見的圖形學問題。
- 渲染管線
- ShadowMap原理、常見的問題以及解決方案
- PBR
- Anti-Aliasing
- Culling
更多內容可參考圖形學面經(jīng),總結的很全面。
圖形API相關
本人主要學習了Vulkan API,在這里總結一下常見的面試問題。
- Vulkan畫一個三角形需要哪些步驟?
考察Vulkan中的基礎概念。
- VkInstance
- VkDevice
- VkQueue
- VkSwapchain
- VkCommandPool & VkCommandbuffer
- VkRenderPass & VkFramebuffer
- VkPipeline & VkPiplineLayout & PSO & VkDescriptorSet VkDescriptorSetLayout VkDescriptorPool
- VkSemaphore VkFence Barrier
- Vulkan中的多線程渲染
Secondary commandbuffer, 多線程 - Vulkan PSO
構建Pipeline需要Pipeline State Objects,包括fixed function的設置、shader設置、pipelineLayout設置,重復利用PSO可以提升性能。 - Vulkan Performance Optimization
- Variable rate shading
- RayTracing API