最近在找工作…面試中遇到了的問題總以為自己會但回答的時候磕磕巴巴,覺得還是要總結一下:
- vector和list的區別
vector list
底層數據結構 基于動態數組實現,元素在內存中連續存儲 基于雙向鏈表實現,元素在內存中非連續存儲,每個節點包含指向前后節點的指針
隨機訪問性能 支持高效的隨機訪問,可直接通過下標或迭代器偏移訪問元素 不支持隨機訪問,需遍歷鏈表尋找目標元素
插入/刪除性能 尾部插入/刪除高效,中間或頭部插入/刪除需要移動后續元素,可能導致內存重分配 任意位置的插入/刪除僅需調整指針,無需移動其他元素。
需要先遍歷到目標位置
內存管理 ? 內存連續,緩存友好(訪問速度快)。
? 擴容時會重新分配內存,導致原有迭代器失效。 ? 內存非連續,緩存不友好(可能引發緩存未命中)。
? 插入/刪除不會導致迭代器失效(除非刪除當前元素)。
空間開銷 僅存儲元素本身,空間效率高 每個節點需要額外存儲兩個指針(前驅和后繼),空間開銷較大(尤其是元素較小時)
迭代器類型 支持隨機訪問迭代器 僅支持雙向迭代器
應用場景 ? 需要頻繁隨機訪問。
? 插入/刪除主要在尾部(如棧結構)。
? 元素類型較小且數量較多(內存連續優勢明顯)。 ? 需要頻繁在任意位置插入/刪除。
? 不需要隨機訪問,僅需順序訪問。
? 元素較大時(避免移動開銷)。 - XML和JSON文件區別
XML JSON
結構 標簽嵌套(如<tag>data</tag>
),結構嚴格,支持屬性(如<name id="1">
) 鍵值對(如{"key": "value"}
),結構更簡潔,不支持屬性,數據直接通過值表示。
可讀性 冗長,標簽重復較多 更緊湊,語法接近代碼對象,易讀
數據體積 文件較大(標簽占用額外空間) 體積更小,傳輸效率高
解析與使用 需復雜解析(如 DOM/SAX),適合強類型數據(如配置文件) 解析簡單(直接映射為對象),廣泛用于 Web API 和前后端交互。
應用場景 文檔型數據(如 HTML)、企業級配置(如 Spring) 輕量級數據交換(如 RESTful API)、移動端和 JavaScript 應用 - 進程和線程的關系
進程 線程
定義 操作系統資源分配的基本單位,獨立內存空間 CPU調度的基本單位,共享進程內存空間
資源分配 獨立擁有代碼、數據、堆棧、文件句柄等資源 共享進程資源,僅獨享寄存器和棧
通信方式 管道/消息隊列/共享內存等 直接讀寫進程內存
性能差異 進程切換開銷大(涉及資源切換) 線程切換開銷小(僅切換上下文)
應用場景 多進程適合需要高隔離性的任務 多線程適合需要頻繁通信的任務 - SQL語言核心要點
DDL(數據定義) CREATE/ALTER/DROP
DML(數據操作) SELECT/INSERT/UPDATE/DELETE
DCL(數據控制) GRANT/REVOKE
TCL(事務控制) COMMIT/ROLLBACK - C++模板(Template)詳解
- 函數模板:
template <typename T>
T max(T a, T b) {return (a > b) ? a : b;
}
2. 類模板:
```cpp
template <class T>
class Stack {
private:std::vector<T> elements;
public:void push(T const&);T pop();
};
**高級特性**:
- 模板特化(特殊類型定制實現)
- 可變參數模板(template<typename... Args>)
- 模板元編程(編譯期計算)
6. **鏈表數據結構解析**
**基礎結構**:
```cpp
struct Node {int data;Node* next;
};
類型 特點 插入復雜度單鏈表 單向遍歷 O(1)
雙向鏈表 雙向指針,可逆序遍歷 O(1)
循環鏈表 尾節點指向頭節點 O(n)
7. **UDP vs TCP對比**
特性 TCP UDP
連接方式 面向連接(三次握手) 無連接
可靠性 保證送達和順序 盡力而為
傳輸形式 字節流 數據報文
頭部大小 20-60字節 8字節
流量控制 滑動窗口機制 無
擁塞控制 多種算法 無
應用場景 網頁瀏覽(HTTP)、文件傳輸(FTP) 視頻流媒體、DNS查詢、在線游戲
8. **結構體(struct)和類(class)區別的詳細解析:**
特性 Struct Class
默認訪問權限 public private
默認繼承權限 public private
語義定位 數據聚合 對象封裝
典型用途 ? 輕量級數據容器(如坐標點、配置參數)
? 無需封裝的數據集合
? C語言兼容性保留 ? 封裝復雜對象(如文件處理器、網絡連接)
? 需要隱藏實現細節的場景
? 面向對象特性(繼承、多態)兩者在內存布局、性能表現上完全一致,區別僅在于編譯器對訪問權限的檢查。
- **模板元編程中的互換性**:```cpptemplate <typename T> // T可以是struct或classvoid process(T obj) {// ...}
9. **重載的核心規則**
? 同名函數/方法:多個函數使用相同的名稱。
? 參數列表必須不同:參數類型、數量或順序至少有一項不同。
? 返回值類型不影響重載:僅返回值不同不足以構成重載。
10. **重載的應用場景**
? 簡化接口:對相似功能提供統一的名稱,例如 `print` 函數處理不同類型數據。
? 增強靈活性:通過不同參數類型或數量,適應多種調用需求。
? 代碼可讀性:用一致的命名表達相同邏輯的不同變體。
11. 在 C++ 中,**模板(Template)** 是一種支持泛型編程的機制,允許編寫與數據類型無關的通用代碼,從而提高代碼復用性。以下是模板的核心用法和關鍵概念的詳細描述:模板的核心作用 泛型編程:通過抽象數據類型,讓同一段代碼適用于多種類型
避免代碼冗余:無需為不同類型重復編寫邏輯相同的代碼(如 int、double版本的排序函數)
類型安全:在編譯期確定類型,比宏或 void* 更安全。
模板的分類與語法 定義:用 template 關鍵字聲明,使用 typename或 class定義泛型參數。
語法:
template<typename T> // 或 template <class T>
返回值類型 函數名(參數列表) { ... } 例子:```cpp
template <typename T>T max(T a, T b) {
return (a > b) ? a : b;}// 調用cout << max(3, 5); // T 推導為 intcout << max(3.5, 2.1); // T 推導為 double類模板定義:允許類成員的數據類型或方法參數泛型化
語法:template <typename T>class 類名 {// 成員變量和方法使用 T};template <typename T>class Stack {private:vector<T> elements;public:void push(T const& elem) {elements.push_back(elem);}T pop() {T elem = elements.back();elements.pop_back();return elem;}};// 使用Stack<int> intStack; // 存儲 int 的棧Stack<string> strStack; // 存儲 string 的棧
模板參數的擴展 多類型參數 template <typename T1, typename T2>void printPair(T1 a, T2 b) {cout << a << ", " << b << endl;}非類型模板參數:允許傳遞常量值(如整型、指針或引用)作為模板參數 template <typename T, int size>class Array {private:T data[size];public:T& operator[](int index) { return data[index]; }};Array<int, 10> intArray; // 固定大小為 10 的數組默認模板參數 template <typename T = int>class Box {T content;};
Box<> defaultBox; // 使用默認類型 int
模板特化 目的:針對特定類型提供優化或特殊實現 // 通用模板template <typename T>void print(T value) {cout << "Generic: " << value << endl;}// 特化版本(處理 char*)template <>void print<char*>(char* value) {cout << "Specialized (char*): " << value << endl;}// 調用int n = 10;print(n); // 調用通用版本char str[] = "Hello";print(str); // 調用特化版本
模板的編譯機制 實例化:模板代碼在編譯時根據具體類型生成實際代碼 // 隱式實例化(由編譯器自動推導)
max(3, 5); // 生成 int max(int, int)
// 顯式實例化(手動指定類型)
template double max<double>(double, double);
模板的注意事項 ? 代碼膨脹:過多模板實例化可能導致編譯后代碼體積增大。
? 編譯錯誤延遲:模板錯誤通常在實例化時才會暴露。
? 聲明與定義需在同一個文件:模板代碼通常直接寫在頭文件中(因編譯機制限制)。
? 4. C++11 后的擴展:支持變長模板參數(Variadic Templates)。
典型應用場景 ? 容器類:如 vector<T>、map<K, V>。
? 算法泛化:如 sort()可處理任何支持比較操作的類型。
? 數學庫:如矩陣運算類 Matrix<T>。
? 智能指針:如 shared_ptr<T>。
通過模板,C++ 實現了高度靈活且類型安全的泛型編程,是 STL(標準模板庫)的基石。合理使用模板可以大幅減少冗余代碼,同時保持高性能。
12. **堆和棧的聯系與區別**
特性 棧(Stack) 堆(Heap)
內存分配方式 由系統自動分配和釋放(如函數調用時) 由程序員手動申請和釋放(如 new/delete)
生命周期 隨函數調用結束自動釋放(局部變量) 需顯式釋放,否則可能內存泄漏
空間大小 較小 較大(受限于操作系統可用內存)
分配效率 快(只需移動棧指針) 慢(需動態查找可用內存塊)
內存碎片 無 可能存在(頻繁分配釋放后)
生長方向向低地址方向增長 向高地址方向增長
線程共享 每個線程獨享自己的棧 進程內所有線程共享堆
存儲內容 局部變量、函數參數、返回地址等 動態分配的對象、數據結構(如數組、對象)
典型應用場景 ? 存儲函數調用的上下文(如函數參數、返回地址)。
? 存放局部變量(生命周期與函數調用綁定)。
? 遞歸調用時,每次調用會生成新的棧幀。 ? 動態分配內存(如 `new`、`malloc`)。
? 存儲大型對象或需要長期存在的數據(如全局數據結構)。
聯系與協同:均為程序運行時提供內存空間,支持數據存儲和操作 ? 棧用于短期、快速的內存需求(如函數調用)
? 棧上的指針變量可以指向堆內存(實現動態內存管理):
int* arr = new int[100]; // 棧變量 arr 指向堆內存
? ? 對用于靈活、長期的內存需求(動態數據結構)
常見問題 ? 棧溢出:遞歸過深或局部變量過大(如超大數組)棧空間不足導致崩潰。 ? 內存泄露:堆內存未釋放。
? 野指針:堆內存釋放后,指針未置空。
適用場景 ? 短期、小數據、自動管理
? 高效、安全、無碎片
? 空間有限、不靈活 ? 長期、大數據
? 容量大、生命周期可控
? 管理復雜、可能泄露或碎片化13. **Qt信號與槽機制的優勢與不足**:
優點:類型安全,信號的參數類型與個數同接受該信號的槽的參數類型和個數相同
松散耦合:激發信號的qt對象不需要關心是否被接受,只需在使用時發出信號即可
靈活:一對多,多對一都可
不足:速度較慢(與回調函數相比)
信號與槽本質:對象間通信的機制,當信號被觸發時通過qt的元對象系統動態鏈接,自動調用與之關聯的槽函數,
14. **Qt的TCP通訊流程**
創建QTcpSocket對象(作為客戶端或服務器的通信端點)
連接到主機(客戶端使用connectToHost函數連接到主機的IP和端口,服務器端使用QTcpServer監聽指定的本地IP和端口號)
建立連接(connected)
讀寫數據(QIODevice中的read write函數)
處理收發數據(啟動一個事件循環,例如QEventLoop處理讀寫操作)
關閉連接
15. **Qt的UDP通訊流程**
創建QUdpSocket對象
若接收數據,必須綁定端口
發送和接收數據
16. **多線程使用方法**
法一:創建一個類從QThread類派生,在子線程類中重寫run函數,處理操作寫入run函數中
在主線程類中創建子線程對象,啟動子線程,調用start函數
法二:使用回調函數,派生線程類中添加回調函數,使用typedef int(*RUNHANDLE )(void *)聲明回調函數句柄,在子線程類中定義開始和結束函數,然后在需要使用線程的類中定義操作數據的回調函數以及調用回調函數的函數……
17. **多線程下信號槽分別在什么線程中執行,如何控制?**
默認直接連接,信號和槽屬于同一個對象,且未使用QueuedConnection等跨線程連接方式
自動連接,信號和槽分別屬于不同對象且處于不同線程,可使用AutoConnection(根據對象所在線程自動選擇直接執行或跨線程執行)或QuenuedConnection(將槽函數放入接收者對象所在事件隊列,在所屬線程中執行)跨線程連接
線程間同步可使用互斥鎖(QMutex)或其他線程同步機制實現對共享資源的訪問控制,確保同一時間只有一個線程可訪問
使用讀寫鎖(QReadWriteLock)允許多個線程同時讀取數據,,但寫入時需獨占訪問,適用于讀多寫少的情況
信號和槽機制:主線程發射信號,子線程中接收信號同步數據
條件變量:允許一個或多個線程等待某個條件為真時再繼續執行,使用QWaitCondition可實現更復雜的線程同步場景,如生產者-消費者模式
原子操作:QAtomicint、QAtomicPointer等保證特定類型的操作是原子性的。
QMutexLocker:對Mutex加鎖或解鎖(unlock)
18. **QObject的作用**
QObject是Qt框架中的一個基類,是所有Qt對象的父類,QObject使得Qt對象可擁有信號與槽機制、事件處理、對象生命周期管理、父子關系以及內存管理,一個QObject對象可通過繼承QObject基類自定義控件或重寫虛函數處理鼠標、鍵盤等事件
19. **Lambda機制**:在Qt信號處理中,Lambda表達式常被用于將信號連接到槽函數或進行信號響應處理,簡潔、方便,可直接在連接信號時即時編寫信號處理邏輯,無需定義槽函數。
20. **C++段錯誤原因:**
空指針解引用:使用一個未初始化或被釋放的指針進行訪問時會導致段錯誤;
數組越界訪問:如果訪問了數組范圍外的元素,超出數組邊界
棧溢出:遞歸調用層次過深、局部變量過多可能導致棧溢出,進而引發段錯誤
內存泄漏和非法內存操作:動態分配內存未釋放或釋放后繼續訪問
內存泄漏排查方式
QtCreator中的內存分析器
使用智能指針(QSharedPointer、QWeakPointer)
在析構函數中手動刪除動態分配的內存
檢查對象的生命周期
21. **Qt三大核心機制**
信號與槽、事件系統(Qt基于事件驅動的編程模型,每個QObject派生類都能接收和處理事件,當用戶執行某操作或系統狀態發生改變時,Qt自動生成并分發相應事件進而響應事件)、對象模型(使用元對象系統支持運行時類型信息和反射,如動態屬性、動態調用等)Qt的元對象編譯系統(MOC)創建新的文件,將源碼轉換為C++編譯器可識別的代碼,當類中需要使用信號槽、對象屬性等擴展功能時可使用,其他情況使用會增大源碼體積,使用方法為繼承QObject,添加Q_OBJECT
22. **虛函數的實現**
虛函數是在父類中定義的一種特殊類型的函數,允許子類重寫該函數以適應自身需求
通過將函數聲明為虛函數,可使繼承層次結構中的每個子類都能使用其自己的實現,提高代碼的可擴展性和靈活性。即同一個函數名可在不同子類中表現出不同的行為。
虛函數可避免靜態綁定,使用父類指針或引用調用子類對象的成員函數時默認進行靜態綁定;
抽象類是一種不能直接實例化的類,只能被其他類繼承并實現其虛函數,通過定義純虛函數可使一個類成為抽象類,強制其子類必須實現該函數。
23. **多態類型**:
編譯時多態(靜態多態):函數重載、運算符重載
運行時多態(動態多態):虛函數、接口和抽象類(純虛函數)
24. **C++中死鎖原因及解決方法**
互斥條件:一次只有一個進程可使用該資源
占有和等待條件:一個進程至少持有一個資源,并在等待獲取其他進程持有的附加資源時,不釋放已占有的資源
不可搶占條件:資源只能由持有它的進程主動釋放
循環等待條件:鏈中每個進程都占有下一個進程所需資源
避免死鎖:一次性獲取所有鎖,同時鎖定
確保資源釋放后再進行下一步操作,避免長時間持有鎖(提前釋放資源)
避免無限等待,設置超時退出操作
25. **項目中界面卡頓,怎么優化?**
防抖:合并高頻刷新請求,避免冗余渲染
節流:設置固定刷新頻率
主線程中僅渲染顯示,子線程中生成分析數據
內存預分配,避免動態內存分配開銷太大
26. **Static和const使用**
Static靜態變量聲明,分為局部靜態變量、全局靜態變量、類靜態成員變量(被類的所有對象共享,必須在類外初始化,不可以在構造函數內初始化),也可修飾類成員函數(所有對象共享該函數,不含this指針,不可使用類中非靜態函數)
Const常量聲明:const和static不可同時修飾類成員函數,const修飾成員函數表示不能修改對象的狀態,static修飾成員函數表示該函數屬于類不屬于對象;
27. **C++指針和引用**
相同點:二者都可用于實現變量的間接訪問,通過引用或指針可修改所指向或引用的對象
引用和指針都可作為函數參數傳遞,以便在函數內部修改實參的值;
不同點:引用是個別名,定義時必須初始化,并且不能被重新綁定到其他對象,指針可通過賦值操作改變其指向的對象
引用必須始終指向一個有效的對象,指針可為空或可選擇性地指向任意類型的對象
引用無需顯式的內存管理,自動綁定到另一個對象并隨該對象的生命周期自動更新,指針需要手動分配和釋放內存
對引用的操作直接影響原始對象,對指針的操作需要解引用才能訪問所指向的對象。
28. **常用數據結構**
Vector:向量,連續存儲,可隨機訪問;
Deque:雙向隊列,連續存儲,隨機訪問;
List:鏈表,內存不連續,不支持隨機訪問;
Stack:棧,不可隨機訪問,只允許在開頭增加或刪除元素;
Queue:單向隊列,尾部增加,開頭刪除;
Set、Map:集合,采用紅黑樹實現,可隨機訪問
Hash_set:哈希表,隨機訪問
29. **封裝、繼承和多態的理解**
封裝是將數據(屬性)和操作數據的方法(函數)結合在一起形成一個對象,通過訪問修飾符(public,private和protected)控制對類成員的訪問。
繼承就是定義一個類(子類或派生類)繼承另一個類(基類或父類)的屬性和方法,繼承可重用代碼,實現代碼的復用和擴展;
多態:即使用統一的接口操作不同的對象,主要通過虛函數和抽象類實現。
30. **重載和重寫的區別**
定義不同:重載是在一個類中定義多個方法,名稱相同但參數列表不同(如參數個數、類型、順序)
重寫是在子類中重新定義父類已經存在的方法,方法名、參數列表和返回類型必須與父類方法相同,但方法體不同;
范圍不同:重載發生在類內部,重寫發生在子類和父類之間
多態性不同:重載屬于靜態綁定,重寫屬于動態綁定
參數和返回類型:重載參數列表必須不同,重寫的返回類型和參數列表必須與父類方法相同;
修飾符限制:重載無要求,重寫對子類方法的訪問權限不能低于父類方法的訪問權限。
31. **信號和信號量的區別?**
信號是一種軟件中斷,通過異步方式通知進程發生了特定事件;
信號量(QSemaphore)是一種整數計數器,用于實現同步與互斥,通過等待(P)和釋放(V)操作控制資源訪問,防止競態條件。創建信號量對象,通過調用acquire方法獲取資源,資源不足,線程阻塞直到資源可用,調用完成后通過release釋放資源,多用于線程同步。
32. **QT Connect 函數的第五個參數:**
1)自動連接(AutoConnection),默認的連接方式,如果信號與槽,也就是發送者與接受者在同一線程,等同于直接連接;如果發送者與接受者處在不同線程,等同于隊列連接。
2)直接連接(DirectConnection),當信號發射時,槽函數立即直接調用。
3)隊列連接(QueuedConnection),當控制權回到接受者所在線程的事件循環時,槽函數被調用。槽函數在接受者所在線程執行,即槽函數與信號接受者在同一線程
4)鎖定隊列連接(BlockingQueuedConnection)
Qt::BlockingQueuedConnection:槽函數的調用時機與Qt::QueuedConnection一致,不過發送完信號后發送者所在線程會阻塞,直到槽函數運行完。接收者和發送者絕對不能在一個線程,否則程序會死鎖。在多線程間需要同步的場合可能需要這個。
5)單一連接(UniqueConnection):避免重復連接,與其他類型按位或結合使用。
33. **C++的智能指針**
Std::shared_ptr:共享所有權(多個指針共享對象),引用計數,計數為0時刪除對象
Std::unique_ptr:獨占所有權(不支持共享引用),自動刪除(超出作用域或重置時刪除對象),可通過轉移構造函數或復制操作符轉移所有權。
Std::weak_ptr:不增加引用計數,可轉換為shared_ptr,轉換時要檢查對象是否存在。
34. **C++信號和槽的調用流程**
Moc查找頭文件中的signal和slots,標記處信號槽,將信號槽信息存儲到staticMetaObject中并按照聲明的順序進行存放,建立索引;
Connect連接,將信號槽的索引信息放到一個雙向鏈表中,彼此配對,emit被調用,調用信號函數,傳遞發送信號的對象指針、元對象指針,信號索引、參數列表到active函數;
Active函數在雙向鏈表中找到所有與信號對應的槽索引,根據索引找到槽函數。