看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《gigigigi (gigigigi)》之銘言: : 開發平台(Platform): (Ex: Win10, Linux, ...) : Linux : 編譯器(Ex: GCC, clang, VC++...)+目標環境(跟開發平台不同的話需列出) : g++ : 額外使用到的函數庫(Library Used): (Ex: OpenGL, ...) : N/A : 問題(Question): : https://www.sendspace.com/file/7gq1j2 這是我程式碼地方 : 我是在把一個 繼承class 打包 so檔案 之後透過 dlopen load 這個so : 如果我把 triangle.hpp 裡面的 virtual void getaa() const; : 的virtual拿掉會編譯階段的link 錯誤無法編譯過 : 但是我把這程式碼單獨寫在同個檔案, 不用so + dlopen 是正常可以編譯過 : 不懂為什麼 so 方式去dlopen link 階段會錯 : 錯誤訊息如下: : g++ -Wall -pedantic -ggdb3 -O0 -std=c++11 -shared -fPIC -o triangles.so : triangle.cpp : g++ -Wall -pedantic -ggdb3 -O0 -std=c++11 main.cpp -o main -ldl -lpthread : /tmp/ccB1oVpb.o: 於函式 main: : dlopen_test/main.cpp:42: 未定義參考到 triangle::getaa() const : collect2: error: ld returned 1 exit status : Makefile:9: recipe for target 'a.out' failed : make: *** [a.out] Error 1 : 謝謝 這個要講起來好複雜....XD 類別的成員函式沒有帶virtual前綴的話 就是一個"函式" 編譯時只要在你主程式的執行中有用到這個函式 就要在編出來的elf裡面留symbol跟code,這個是靜態連結的主要工作 所以你下參數編main的時候,他找不到getaa的code不給過 這是很正常的情況,因為你沒帶有getaa的triangle.cpp給他 那反過來看帶virtual的case,virtual function實際上是一個"函式指標" (以下簡稱vptr) 他跟函式最大的不同是-----他要指到函式才能用(廢話) 那既然還是要指到函式,似乎還是需要知道getaa的code才能夠編 這樣看起來應該也是編不過才對呀? https://wandbox.org/permlink/OLqeSdn0eDyekIZW (實際上應該是要像這個樣子才對) 這個關鍵點在於vptr真正指到function的時機是在建構子內。 上面那段程式因為建構子在TestClass建Instance的時候就會呼叫到 有呼叫到就要把vptr指過去真正的Test() 所以在連結期main.cpp就要知道Test()的長相 而原PO寫的程式因為建構子是包在create裡面 create又是用dlsym抓出來後再做強轉型 所以compiler掃呼叫函式的時候追到dlsym這邊就斷掉了 他不會需要知道建構子,也就不負責做vptr指到getaa的動作 那底下那行trs->getaa()就只是一個把vptr裡的值取出來call的動作而已 至於vptr裡面的東西到底是指到getaa還是kill_the_kernel 這就跟編譯和連結無關,是執行期的問題了,大不了segment fault嘛:P -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 123.193.54.11 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1532750478.A.51E.html
gigigigi: 感謝 解惑 07/29 20:57