距離上次發部落格已經有一年半了,轉眼間我也是從做影象研究到了做遊戲開發,說起來看看前面的博文,本來就有前兆的東西呢(笑)......因為主要還是在使用虛幻引擎,所以C++的東西會碰到多一些。
以後程式技術方面的文章就放部落格,遊戲設計相關的雜談就放知乎那邊吧,博主的知乎可以通過友鏈過去。
B站那邊的賬號也打算開始復活,後面是更新遊戲設計雜談類的視訊還是更新虛幻技術方面的視訊還在猶豫不決......
有時我們需要把自己的程式交給第三方呼叫,但是又不想被別人看到自己的具體實現程式碼,就封裝成庫給別人使用。庫有動態連結庫和靜態連結庫,區別是動態連結庫可以在程式執行時動態連結,而靜態連結庫相當於.cpp檔案,在編譯時的連結階段就連結進去了。
系統:Window 10
IDE:VS2022
如果在使用的是其他IDE的,看完這個其實自己應該也能知道用其他IDE該怎麼操作,其實就是一個對編譯和連結過程的理解深度的問題,懂了在哪裡都能自己封裝和使用庫的。
這邊的演示有中文路徑,VS對中文路徑支援得確實還挺可以的,不會報錯。不過建議大家還是儘量別這樣了,就怕萬一你那邊對中文路徑支援不好,編譯出問題。
我準備了一個Point類,就當做是要給別人用的,現在我就把這個類封裝成靜態庫。
//Point.h #pragma once #include <utility> typedef std::pair<int, int> Coordinate; class Point { private: Coordinate location; public: Point(); Point(int x, int y); Coordinate GetLocation(); int GetX() const; int GetY() const; virtual Point operator + (const Point& B) const; virtual Point operator - (const Point& B) const; };
//Point.cpp #include "Point.h" Point::Point() : location(Coordinate(0, 0)) { } Point::Point(int x, int y): location(Coordinate(x, y)) { } Coordinate Point::GetLocation() { return location; } int Point::GetX() const { return location.first; } int Point::GetY() const { return location.second; } Point Point::operator+(const Point& B) const { return Point(GetX()+B.GetX(), GetY()+B.GetY()); } Point Point::operator-(const Point& B) const { return Point(); }
平常我們是編譯成可執行檔案(即.exe),現在我們設定一下,改成編譯成靜態庫(即.lib)。
這個設定在VS2022裡是這樣的:
右擊專案->屬性->設定屬性->常規->設定型別->改為靜態庫
這樣我們編譯出來的東西就不是.exe檔案,而是.lib檔案了,也就是靜態連結庫。
這邊在VS2022裡,編譯就是生成。
就跟編譯普通程式一樣,編譯成功。
自己翻翻專案下面的資料夾,能找到編譯出來的靜態庫的。
我這邊是 專案根目錄/x64/Debug/專案名.lib,就是下圖裡的那個Point.lib,這就是靜態庫。
其實就是把標頭檔案跟靜態庫一起給別人就行了,靜態庫的作用跟.cpp檔案差不多,使用時就是包含標頭檔案,然後連結到靜態庫把實現關聯起來即可。
新建了個專案,這個專案要用到我的那個Point類,為了方便包含標頭檔案,我把上邊的那個有Point.h有和Point.lib的資料夾挪到新專案資料夾下了。
新建了個程式,要用到我寫的那個Point類,那就先包含Point.h,裡面有關於Point類的宣告。
//使用靜態庫.cpp
#include <iostream> #include "大摸魚師千里的Point類/Point.h" using namespace std; int main() { Point a(1, 2); Point b(3, 4); Point c = a + b; cout << c.GetX() << ", " << c.GetY() << endl; return 0; }
但是這個時候編譯還是通不過的,如下圖報了「無法解析外部符號」,是連結的錯誤來的。標頭檔案雖然有Point類宣告資訊,但沒有實現的資訊,實現的資訊在靜態庫裡,但是現在連結器還找不到靜態庫,所以報錯了。
有兩種方法,一種是在原始檔裡設定,另一種是在專案裡設定。
先講在原始檔裡設定,其實就是加個編譯頭告訴連結器靜態庫的路徑而已,語法如下:
#pragma comment(lib, 你的靜態庫路徑)
這樣子連結器在搜尋預設的庫檔案路徑外,還會搜你這裡的設的靜態庫路徑。
在我這裡,加了就是會變成這樣:
//使用靜態庫.cpp #include <iostream> #include "大摸魚師千里的Point類/Point.h" using namespace std; #pragma comment(lib, "大摸魚師千里的Point類/Point.lib") int main() { Point a(1, 2); Point b(3, 4); Point c = a + b; cout << c.GetX() << ", " << c.GetY() << endl; return 0; }
因為連結器找到路徑了,編譯就能過了,程式正常執行,效果如下。
VS2022裡是這麼設定連結器搜尋的庫目錄的
先是設定庫的目錄,專案屬性->VC++目錄->庫目錄->編輯->新行->把靜態庫所在目錄新增進去
因為這個時候只是加了搜尋的庫目錄,但是還沒有具體到哪個庫,可以像上邊那樣用編譯頭來指定,就是不加相對路徑直接指定靜態庫,就像這樣。
#pragma comment(lib, "Point.lib")
現在講怎麼在專案裡設定具體到指定庫。
專案屬性->連結器->輸入->附加依賴項->編輯->新增你的庫
設完就是不加編譯頭也能編譯執行程式了,這是效果
以上就是C++封裝庫和使用的全部內容了,覺得有學到的話可以點個贊嘿嘿。