Tổng hợp 57 câu hỏi phỏng vấn C++ kèm đáp án chi tiết, song ngữ Việt–Anh — sắp xếp từ cơ bản đến nâng cao. Ôn luyện miễn phí, tự động lưu tiến độ.
C++ mở rộng C với: - OOP: class, kế thừa, đa hình, encapsulation. - Tham chiếu (&): alias an toàn hơn con trỏ raw. - new/delete thay malloc/free — gọi constructor/destructor. - Templates: code generic type-safe. - Ngoại lệ (try/catch): thay if-else kiểm tra lỗi…
Tham chiếu là alias của một biến đã tồn tại — cùng địa chỉ, cùng giá trị, khác tên gọi. Khác con trỏ: Tham chiếu Con trỏ --------- Null Không được null Có thể null Reassign Không đổi được target Có thể Cú pháp dùng…
new malloc --------- Loại toán tử C++ hàm C Constructor Có, gọi tự động Không gọi Kiểu trả về typed pointer void Khi thất bại throw std::badalloc trả nullptr Giải phóng delete / delete[] free() Không trộn lẫn: new phải delete, malloc phải free. Trong…
Stack: vùng nhớ tĩnh, cấp phát tự động khi hàm được gọi, giải phóng khi hàm trả về. Truy cập nhanh, kích thước hạn chế (thường vài MB). Heap: vùng nhớ động, cấp phát qua new/malloc, phải giải phóng thủ công bằng delete/free. Kích thước…
inline gợi ý compiler chèn thân hàm tại điểm gọi thay vì tạo stack frame mới — giảm overhead function call với hàm nhỏ. Khi nên dùng: hàm rất nhỏ (1–3 dòng), được gọi nhiều trong hot path. Khi không nên: hàm lớn — code…
Function overloading: nhiều hàm cùng tên, khác signature (số/kiểu tham số). Compiler chọn đúng bản tại compile-time. Operator overloading: tái định nghĩa toán tử (+, <<, ==, ...) cho kiểu tự định nghĩa. Khác biệt với overriding: override là ghi đè hàm ở lớp con…
Dangling pointer là con trỏ trỏ tới vùng nhớ đã bị giải phóng — đọc/ghi vào đó là undefined behavior (crash hoặc corrupt dữ liệu ngầm). Cách tránh tốt hơn: dùng smart pointer (std::uniqueptr, std::sharedptr) — tự giải phóng khi ra scope, không bao giờ…
RAII (Resource Acquisition Is Initialization): gắn vòng đời tài nguyên (bộ nhớ, file, lock...) vào vòng đời một object trên stack. Cấp tài nguyên trong constructor, giải phóng trong destructor. Khi object ra khỏi scope, destructor tự chạy — tài nguyên được trả lại kể…
uniqueptr: sở hữu độc quyền — chỉ có 1 owner, không copy được, chỉ move. Khi ra scope, tự delete. sharedptr: sở hữu chia sẻ — nhiều pointer cùng quản lý 1 object qua reference count. Khi count về 0 thì object bị xoá. weakptr:…
Shallow copy (mặc định của compiler): copy từng byte — với member là pointer, cả hai object cùng trỏ về cùng vùng nhớ. Giải phóng một cái → cái kia thành dangling pointer. Deep copy: copy cả nội dung mà pointer trỏ tới — hai…
Đọc từ phải sang trái: "const" gần nhất áp dụng cho phần tử đứng trước nó. Ví dụ thực tế: Hình dung: const trước = bảo vệ dữ liệu; const sau = bảo vệ địa chỉ.
1. Encapsulation (Đóng gói): gom data + method vào class; che giấu chi tiết nội bộ qua private/protected. 2. Inheritance (Kế thừa): class con kế thừa thuộc tính/method từ class cha → tái sử dụng code, mở rộng dễ. 3. Polymorphism (Đa hình): cùng interface,…
Virtual function: có cài đặt mặc định ở base class, class con có thể override. Pure virtual function (= 0): không có cài đặt ở base class, class con bắt buộc override. Class chứa pure virtual → abstract class, không thể tạo instance trực tiếp.
Khi class có ít nhất 1 virtual function, compiler tạo một vtable — mảng các con trỏ hàm cho class đó. Mỗi object có thêm một hidden pointer (vptr) trỏ tới vtable của class thực sự. Khi gọi s-area() (s là Shape trỏ Circle): đọc…
Diamond problem xảy ra khi class D kế thừa từ B và C, cả hai đều kế thừa từ A. Kết quả: D có 2 bản sao của A, gây nhập nhằng. Giải pháp: virtual inheritance — A chỉ tồn tại 1 lần trong D.…
STL (Standard Template Library) là thư viện chuẩn C++ cung cấp các cấu trúc dữ liệu và thuật toán đã được tối ưu hoá, dùng qua templates. 3 thành phần chính: 1. Containers: lưu trữ dữ liệu. - Sequence: vector, list, deque, array - Associative:…
std::vector là dynamic array — tự quản lý vùng nhớ liên tục trên heap, tự resize khi cần. - size(): số phần tử hiện có. - capacity(): số phần tử có thể chứa trước khi cần cấp phát lại bộ nhớ. Khi size == capacity…
std::map std::unorderedmap --------- Cấu trúc nội bộ Red-Black Tree Hash Table Thứ tự key Có thứ tự Không có thứ tự find / insert / erase O(log n) O(1) trung bình, O(n) worst Iterator hợp lệ giữ nguyên sau insert có thể invalid sau rehash…
Iterator là object đóng vai trò con trỏ tổng quát để duyệt container — tách algorithm ra khỏi cấu trúc nội bộ của container. 5 loại cổ điển (từ ít đến nhiều khả năng): Loại Đọc Ghi ++ -- [] Ví dụ --------------------- Input Có…
Lambda là hàm ẩn danh inline, thường dùng cùng STL algorithm. Lưu ý: capture by reference khi lambda tồn tại lâu hơn biến captured → dangling reference. Dùng capture by value hoặc std::sharedptr để an toàn.
Trước C++11, truyền object lớn (vector, string) vào hàm luôn copy → tốn kém. Move semantics cho phép "chuyển nhượng" tài nguyên thay vì copy. - lvalue: object có địa chỉ xác định (có thể lấy &). - rvalue: giá trị tạm thời, không có…
auto: yêu cầu compiler tự suy kiểu (type deduction) từ biểu thức khởi tạo. Range-based for (C++11): Lưu ý: auto& x giữ reference; auto x luôn copy kể cả với reference source.
Trước C++11, NULL thường là macro define NULL 0 — kiểu int, gây nhập nhằng khi overloading. nullptr là literal kiểu std::nullptrt, chuyển đổi ngầm về bất kỳ pointer type nào nhưng không về int. Quy tắc hiện đại: luôn dùng nullptr thay NULL hoặc…
Undefined behavior là hành vi mà chuẩn C++ không quy định kết quả — compiler được phép làm bất cứ điều gì: crash, kết quả sai, hoặc tình cờ "chạy đúng". Ví dụ phổ biến: Tình huống Lý do UB ------ int p = nullptr;…
Memory leak xảy ra khi bộ nhớ được cấp phát bằng new/malloc nhưng không bao giờ được giải phóng — chương trình dần dần ăn hết RAM. Nguyên nhân thường gặp: - Quên delete (đặc biệt khi có exception hoặc early return) - Mất pointer…
Cast Thời điểm Dùng khi --------- staticcast compile-time chuyển đổi an toàn: int→double, upcast, void→T dynamiccast runtime (RTTI) downcast qua hierarchy — trả nullptr/throw nếu sai kiểu reinterpretcast compile-time đọc lại raw bit theo kiểu khác — pointer↔integer, hoàn toàn unsafe constcast compile-time thêm/bỏ const/volatile…
explicit ngăn compiler tự động chuyển đổi ngầm (implicit conversion) khi gọi constructor hoặc toán tử chuyển đổi. Quy tắc thực tế: constructor có 1 tham số nên khai báo explicit trừ khi conversion ngầm đó có ý nghĩa rõ ràng (ví dụ std::string từ…
Const member function được khai báo với const sau danh sách tham số — cam kết không thay đổi trạng thái object (không sửa any non-mutable member). Tại sao quan trọng (const-correctness): - Cho phép truyền object bằng const& và vẫn gọi được các getter.…
friend cho phép một hàm hoặc class truy cập trực tiếp các thành viên private/protected của class khác — phá encapsulation có kiểm soát. Khi dùng hợp lý: - Operator overloading cần truy cập private của cả 2 bên (ví dụ operator<<). - Unit test…
static member (variable hoặc function) thuộc về class, không thuộc về instance cụ thể nào — tất cả object chia sẻ cùng 1 bản. Đặc điểm: - Static member variable phải định nghĩa ngoài class (trừ inline static C++17). - Static method không có this…
STL algorithms hoạt động trên bất kỳ container nào qua iterator — tách logic khỏi cấu trúc dữ liệu. Lưu ý: dùng std::sort trên std::list sẽ không compile — list không có random access iterator; phải dùng list.sort().
std::set std::multiset --------- Duplicate keys Không cho phép Cho phép Cấu trúc Red-Black Tree Red-Black Tree insert O(log n) O(log n) Thứ tự Có (tăng dần mặc định) Có Dùng set khi: cần tập hợp phần tử duy nhất, kiểm tra membership O(log n). Dùng…
Cơ chế: Stack unwinding: khi exception được throw, destructor của mọi object trên stack được gọi theo thứ tự ngược — đây là lý do RAII hoạt động ngay cả khi có exception. noexcept: khai báo hàm không ném exception. Nếu vi phạm → std::terminate()…
std::optional<T đại diện cho giá trị có thể có hoặc không — thay thế cho nullptr, -1, hoặc out-param bool. Dùng khi: hàm có thể thất bại mà không phải lỗi (lookup, parse), optional config field. Không dùng khi: lỗi thực sự — dùng exception;…
std::variant là type-safe union — tại một thời điểm chỉ giữ một giá trị, nhưng luôn biết kiểu đang giữ là gì. Khác union: union std::variant --------- Type tracking Không Có Destructor Không tự gọi Tự gọi An toàn Không (UB nếu đọc sai kiểu)…
std::stringview là view không sở hữu (non-owning view) vào một chuỗi ký tự — chỉ là con trỏ + độ dài, không copy. So với const std::string&: const std::string& std::stringview --------- const char argument Tạo temporary string Không tạo Substring Tạo string mới Zero-copy Non-null-terminated…
std::initializerlist<T cho phép khởi tạo object bằng cú pháp {...} (brace initialization) với nhiều giá trị — đặc biệt hữu ích cho container. Lưu ý về priority: Hành vi ưu tiên initializerlist constructor khi dùng {} là nguồn gốc nhiều bug ngầm trong C++11.
Pass-by-value Pass-by-reference (&) Pass-by-pointer () ------------ Copy Luôn copy Không copy Không copy (copy địa chỉ) Null Không thể null Không thể null Có thể null Reassign Không ảnh hưởng caller Không reassign target Có thể trỏ chỗ khác Dùng Kiểu nhỏ (int, bool) Object…
Namespace là vùng tên để nhóm các identifier — tránh xung đột tên khi dùng nhiều library. using namespace std; đưa toàn bộ tên trong std vào scope hiện tại — tiện cho ví dụ nhỏ nhưng nguy hiểm trong code thực. Vấn đề khi…
Ba container adapter trong STL — xây trên một container bên dưới (mặc định deque hoặc vector). Container Thứ tự Mặc định dùng Push Pop Top ------------------ stack LIFO deque O(1) O(1) top() queue FIFO deque O(1) O(1) front() priorityqueue Heap (max ở đầu) vector…
Khác biệt kỹ thuật duy nhất: mức truy cập mặc định. - struct: thành viên và kế thừa mặc định public. - class: mặc định private. Ngoài ra hai từ khoá hoàn toàn tương đương — struct vẫn có method, constructor, kế thừa, template như…
Ưu tiên const (Effective C++, Item 2: "Prefer consts to defines"). define chỉ là thay thế văn bản ở giai đoạn tiền xử lý: - Không có kiểu, không có scope — không tuân theo namespace hay class. - Tên biến mất trước khi compiler…
Compile-time (static polymorphism): lời gọi được phân giải lúc biên dịch — qua function overloading, template, CRTP. Không tốn chi phí runtime và có thể inline, nhưng kiểu phải biết trước lúc biên dịch. Runtime (dynamic polymorphism): phân giải lúc chạy qua virtual function +…
Khi xoá object dẫn xuất qua con trỏ lớp cơ sở: Nếu destructor của Base không virtual, chỉ ~Base() chạy — phần Derived không được huỷ → rò rỉ tài nguyên / undefined behavior. Đánh dấu virtual ~Base() để delete tra vtable và gọi đúng…
volatile báo compiler rằng giá trị biến có thể đổi do tác nhân ngoài luồng chương trình: thanh ghi phần cứng, interrupt/ISR, memory-mapped I/O. Compiler khi đó không được tối ưu kiểu cache biến vào thanh ghi hay bỏ đi lần đọc "thừa" — mỗi…
- delete: huỷ một object đơn (cấp bằng new). Gọi 1 destructor rồi giải phóng vùng nhớ. - delete[]: huỷ một mảng (cấp bằng new[]). Gọi destructor cho từng phần tử rồi giải phóng. Phải khớp cặp: new↔delete, new[]↔delete[]. Trộn lẫn (dùng delete trên mảng,…