● Khóa nâng cao · C++ 1 kèm 1 · 23 buổi PRG1006

Học Lập Trình C++
Buổi |

Lộ trình rút gọn 1 tháng: bù Hàm, bắc cầu C → C++, làm chủ con trỏ & bộ nhớ động, rồi toàn bộ OOP. Mỗi khái niệm có ví dụ chạy thật và bài tập 3 mức.

main.cpp — Dev-C++ / VS Code
Bắt đầu Buổi 0 ↓
BUỔI 0

Bù kiến thức C: Hàm (Functions)

1 Vì sao cần hàm?

Khi chương trình lớn dần, viết hết trong main sẽ rối và lặp lại. Hàm giúp:

♻️
Tái sử dụngViết 1 lần, gọi nhiều lần
🧩
Chia nhỏBài toán lớn → phần dễ quản lý
🔧
Dễ sửaSửa 1 chỗ, tác dụng mọi nơi gọi
Buổi này học Hàm trong C làm nền — Buổi 6 sẽ mở rộng sang C++ (tham chiếu). Nắm chắc ở đây thì về sau không hụt.

2 Cấu trúc một hàm

📄 giaithua.c

      

3 Truyền theo giá trị — "hạt giống" cho Buổi 2 & 6

Khi truyền tham số theo giá trị, hàm làm việc trên bản sao — sửa bên trong hàm KHÔNG ảnh hưởng biến gốc. Cùng xem hàm swap "thất bại có kiểm soát":

📄 swap_value.c

      
Thấy chưa? x, y không đổi. Hãy nhớ câu hỏi "làm sao để hàm sửa được biến gốc?" — Buổi 2 (con trỏ)Buổi 6 (tham chiếu) sẽ trả lời.

4 Biến cục bộ & biến toàn cục (scope)

💡 Ưu tiên biến cục bộ + truyền qua tham số/return, thay vì lạm dụng biến toàn cục.

🏠 Bài tập về nhà

Buổi 0 — Hàm trong C

3 bài theo độ khó tăng dần. Viết hàm rồi gọi trong main, in kết quả giống mẫu.

Bài 1🟢 Dễ

Hàm tổng 1 → n

Viết hàm tong(int n) trả về tổng các số từ 1 đến n.

🖥️ Kết quả mẫu
tong(5) = 15

💡 Dùng vòng lặp cộng dồn rồi return.

Bài 2🟡 Vừa

Trung bình cộng mảng

Viết hàm float trungBinh(int a[], int n) trả về trung bình cộng các phần tử.

🖥️ Kết quả mẫu
Mang: 4 6 8 2
Trung binh = 5.00

💡 Tổng là int, chia dùng ép kiểu (float)tong / n.

Bài 3🔴 Khó (sáng tạo)

Số chính phương

Viết hàm int laChinhPhuong(int n) trả về 1 nếu n là số chính phương (vd 1,4,9,16…), ngược lại 0. Thử với vài số.

🖥️ Kết quả mẫu
16 -> la so chinh phuong
10 -> khong

💡 Gợi ý: tìm i sao cho i*i == n (i chạy tới khi i*i ≥ n).

BUỔI 1

Từ C sang C++ — làm quen cú pháp mới

1 Nhập / xuất kiểu C++: cin & cout

C++ = C + thêm tính năng. Cái mới đầu tiên là cách nhập/xuất — thay printf/scanf bằng cout/cin:

📄 hello.cpp

      

2 Kiểu bool & string

Yên tâm: con trỏ, hàm, mảng, vòng lặp, if/else — y hệt C. Hôm nay chỉ đổi cách nhập/xuất và thêm vài kiểu.

3 Thực hành: nhập tên & tuổi

📄 chao.cpp

      
🏠 Bài tập về nhà

Buổi 1 — Từ C sang C++

Chuyển tư duy sang cin/cout. Làm 3 bài, in ra giống mẫu.

Bài 1🟢 Dễ

Lời chào

Nhập tên (string), in ra "Xin chao <ten>!" bằng cout.

🖥️ Kết quả mẫu
Nhap ten: Bo
Xin chao Bo!

💡 string ten; cin >> ten;

Bài 2🟡 Vừa

Máy tính 2 số

Nhập 2 số thực, in tổng, hiệu, tích, thương bằng cout.

🖥️ Kết quả mẫu
a = 6, b = 4
Tong = 10  Hieu = 2
Tich = 24  Thuong = 1.5

💡 Dùng double cho phép chia ra số lẻ.

Bài 3🔴 Khó (sáng tạo)

Bảng cửu chương C++

Nhập số n (1–9), in bảng cửu chương của n bằng cout (chuyển từ code C sang C++).

🖥️ Kết quả mẫu
Nhap n: 3
3 x 1 = 3
...
3 x 10 = 30

💡 Vòng lặp for giống C, chỉ đổi phần in sang cout.

BUỔI 2

Con trỏ cơ bản

1 Con trỏ là gì?

Mỗi biến là một ô nhớđịa chỉ. Con trỏ là biến chứa địa chỉ của một biến khác.

a (giá trị)
10
tại địa chỉ 0x100
p (con trỏ)
0x100
trỏ tới a →
✏️ Luôn vẽ hình: ô nhớ — địa chỉ — mũi tên. Con trỏ là chủ đề phải "nhìn thấy" mới hiểu.

2 Toán tử & (địa chỉ) và * (truy xuất)

📄 contro.cpp

      

3 Con trỏ NULL & con trỏ "hoang" (wild)

4 Thực hành: swap bằng con trỏ (giải bài toán Buổi 0!)

Nhớ hàm swap theo giá trị thất bại ở Buổi 0 chứ? Giờ dùng con trỏ để hàm sửa được biến gốc:

📄 swap_ptr.cpp

      
So sánh trực tiếp: bản giá trị (Buổi 0) không đổi được x, y — bản con trỏ đổi thành công. Đó là sức mạnh của con trỏ.
🏠 Bài tập về nhà

Buổi 2 — Con trỏ cơ bản

Vẽ sơ đồ bộ nhớ ra giấy trước khi code. Làm 3 bài.

Bài 1🟢 Dễ

Đọc qua con trỏ

Khai báo int a = 25;, cho con trỏ p trỏ tới a, in giá trị a qua *p.

🖥️ Kết quả mẫu
Gia tri qua con tro: 25

💡 int *p = &a; cout << *p;

Bài 2🟡 Vừa

Ghi qua con trỏ

Dùng con trỏ để đổi giá trị của biến a, in a trước và sau khi đổi.

🖥️ Kết quả mẫu
Truoc: a = 25
Sau:   a = 99

💡 *p = 99; sẽ sửa chính biến a.

Bài 3🔴 Khó (sáng tạo)

Hàm swap + sơ đồ bộ nhớ

Viết hàm swap(int *a, int *b) hoán đổi 2 biến. Vẽ tay sơ đồ ô nhớ (địa chỉ + mũi tên) mô tả trước/sau khi swap.

🖥️ Kết quả mẫu
Truoc: x = 3, y = 7
Sau:   x = 7, y = 3

💡 Gọi hàm bằng swap(&x, &y); — nhớ dấu &.

BUỔI 3

Con trỏ nâng cao + luyện tập

1 Quan hệ mảng — con trỏ

Tên mảng thực chất là địa chỉ phần tử đầu. Vì vậy:

a[i]  ⟺  *(a + i) — hai cách viết cho cùng một thứ.
📄 duyet_contro.cpp

      

2 Con trỏ đôi (int **p)

Con trỏ cũng là biến → có địa chỉ → có thể có con trỏ trỏ tới nó. Vẽ 3 tầng ô nhớ:

📦
agiá trị: 5
👉
ptrỏ tới a
👉👉
pptrỏ tới p
📄 contro_doi.cpp

      

💡 *pp ra con trỏ p; **pp ra giá trị a. Con trỏ đôi sẽ dùng ở Buổi 6 khi hàm cần sửa chính con trỏ được truyền vào.

3 Thực hành nhanh

Duyệt mảng bằng con trỏ thay vì chỉ số, in từng phần tử.
In địa chỉ từng phần tử (&a[i]) để thấy bước nhảy đúng bằng sizeof(int).
🏠 Bài tập về nhà

Buổi 3 — Con trỏ nâng cao

Làm 3 bài. Bài khó chuẩn bị cho Buổi 6 (con trỏ đôi trong hàm).

Bài 1🟢 Dễ

Duyệt mảng bằng con trỏ

Cho mảng {5, 10, 15, 20}, dùng con trỏ và *(p + i) in các phần tử.

🖥️ Kết quả mẫu
5 10 15 20

💡 int *p = a; rồi lặp in *(p + i).

Bài 2🟡 Vừa

In địa chỉ phần tử

In địa chỉ từng phần tử của mảng int để thấy chúng cách nhau đúng 4 byte.

🖥️ Kết quả mẫu (địa chỉ minh họa)
a[0] tai 0x100
a[1] tai 0x104
a[2] tai 0x108

💡 In &a[i] (hoặc a + i).

Bài 3🔴 Khó (sáng tạo)

Con trỏ đôi trong hàm

Viết hàm dùng con trỏ đôi (int **pp) để thay đổi giá trị mà một con trỏ ở hàm gọi đang trỏ tới.

🖥️ Kết quả mẫu
Truoc: *p = 5
Sau:   *p = 100

💡 Truyền &p vào hàm; bên trong dùng **pp = 100;

BUỔI 4

Cấp phát bộ nhớ động

1 Stack vs Heap

📚
Stack

Biến cục bộ, tự tạo & tự hủy khi hàm kết thúc. Kích thước cố định lúc biên dịch.

🗄️
Heap

Xin bộ nhớ lúc chạy bằng new, tồn tại tới khi ta delete. Linh hoạt kích thước.

2 Cấp phát mảng động

📄 mang_dong.cpp

      
Sau delete[] a; mà vẫn dùng a[i]dangling pointer (con trỏ "treo"), giá trị rác hoặc crash. Xóa xong thì đừng đụng nữa.
🏠 Bài tập về nhà

Buổi 4 — Cấp phát động

Nhớ: mỗi new một delete. Làm 3 bài.

Bài 1🟢 Dễ

Mảng động cơ bản

Nhập n, cấp phát mảng n số bằng new, nhập giá trị, in lại rồi delete[].

🖥️ Kết quả mẫu
Nhap n: 3
Nhap: 5 8 2
Mang: 5 8 2

💡 int *a = new int[n];delete[] a;

Bài 2🟡 Vừa

Tổng & trung bình mảng động

Nhập n phần tử (mảng động), tính tổng và trung bình, giải phóng đúng cách.

🖥️ Kết quả mẫu
n = 4, mang: 4 6 8 2
Tong = 20, TB = 5.00

💡 Dùng double cho trung bình. Nhớ delete[] cuối.

Bài 3🔴 Khó (sáng tạo)

Săn lỗi memory leak

Cho đoạn code cấp phát mảng nhưng quên delete[]. Chỉ ra chỗ rò rỉ và sửa lại cho đúng.

🖥️ Yêu cầu
- Chi ra dong bi leak
- Them delete[] dung cho

💡 Tìm new nào chưa có delete tương ứng.

BUỔI 5 · 🏁 CHECKPOINT

Con trỏ & Bộ nhớ động

🏁 Buổi củng cố — KHÔNG học kiến thức mới

Đây là mốc quan trọng. Nếu chưa vững con trỏ / newdelete, lặp lại buổi này trước khi đi tiếp, đừng vội sang Buổi 6.

📄 checkpoint.cpp (demo)

      
Tiêu chí qua buổi: tự viết được chương trình mảng động độc lập & giải thích đúng lý do dùng new/delete.
🎯 Bài kiểm tra

Buổi 5 — Checkpoint

Làm dần theo 3 mức. Đây là "đề" củng cố toàn bộ con trỏ & heap.

Mức 1🟢 Dễ

Nhập & in mảng động

Nhập số lượng điểm, cấp phát mảng động, nhập & in lại, giải phóng.

🖥️ Kết quả mẫu
So diem: 3
Diem: 8 7 9

💡 Dựng khung new → nhập → in → delete[].

Mức 2🟡 Vừa

Trung bình · Max · Min

Thêm tính điểm trung bình, tìm điểm cao nhất & thấp nhất.

🖥️ Kết quả mẫu
TB = 8.00
Max = 9, Min = 7

💡 Khởi tạo max = min = a[0] rồi duyệt.

Mức 3🔴 Khó (sáng tạo)

Giải thích & không leak

Hoàn thiện chương trình, đảm bảo không rò rỉ bộ nhớ, và tự viết 2–3 câu giải thích vì sao dùng mảng động.

🖥️ Yêu cầu
- 1 new ↔ 1 delete[]
- Giai thich ly do dung heap

💡 Rà lại: mọi new đều có delete trước khi kết thúc.

BUỔI 6

Hàm & tham chiếu + truyền mảng

1 Tham chiếu (reference) — cách thứ 3

Buổi 0 truyền theo giá trị (không sửa được gốc), Buổi 2 dùng con trỏ. C++ có thêm tham chiếu — là "bí danh (alias)" của biến gốc, viết gọn hơn con trỏ:

📄 swap_ref.cpp

      
Cách truyềnSửa được biến gốc?Cú pháp gọi
Giá trị❌ Khôngswap(x, y)
Con trỏ✅ Cóswap(&x, &y)
Tham chiếu✅ Có (gọn nhất)swap(x, y)

2 Truyền mảng vào hàm

Tên mảng "suy biến" thành con trỏ → sửa phần tử trong hàm ảnh hưởng mảng gốc (như tham chiếu tự nhiên):

📄 mang_ham.cpp

      
Lỗi kinh điển: hàm trả về con trỏ trỏ tới biến cục bộ → biến bị hủy khi hàm kết thúc → con trỏ treo. Muốn trả mảng mới thì cấp phát động (Buổi 4) bên trong hàm.
🏠 Bài tập về nhà

Buổi 6 — Hàm & tham chiếu

Chọn đúng cách truyền tham số cho từng bài. Làm 3 bài.

Bài 1🟢 Dễ

Swap bằng tham chiếu

Viết hàm swap(int &a, int &b) hoán đổi 2 biến, gọi swap(x, y).

🖥️ Kết quả mẫu
x = 7, y = 3

💡 Gọn hơn con trỏ — không cần dấu & khi gọi.

Bài 2🟡 Vừa

Hàm sửa mảng

Viết hàm nhân đôi mọi phần tử của một mảng (sửa trực tiếp mảng gốc).

🖥️ Kết quả mẫu
Truoc: 1 2 3
Sau:   2 4 6

💡 void nhanDoi(int a[], int n).

Bài 3🔴 Khó (sáng tạo)

Trả 2 kết quả cùng lúc

Viết hàm nhận 2 số và trả về đồng thời tổng và tích qua tham chiếu.

🖥️ Kết quả mẫu
a = 3, b = 4
Tong = 7, Tich = 12

💡 void tinh(int a, int b, int &tong, int &tich).

BUỔI 7

Đối số mặc định & Nạp chồng hàm

1 Đối số mặc định (default argument)

Cho tham số một giá trị sẵn — khi gọi không truyền thì dùng giá trị đó:

📄 default_arg.cpp

      

2 Nạp chồng hàm (overload)

Nhiều hàm cùng tên, khác số lượng/kiểu tham số — trình biên dịch tự chọn đúng hàm:

📄 overload.cpp

      
⚠️ Không thể overload chỉ khác kiểu trả về — phải khác tham số.
🏠 Bài tập về nhà

Buổi 7 — Overload hàm

Làm 3 bài.

Bài 1🟢 Dễ

Lời chào có mặc định

Viết hàm chao(string ten, string loi = "Xin chao"), gọi cả có và không truyền lời chào.

🖥️ Kết quả mẫu
Xin chao, Bo!
Hello, An!

💡 Tham số mặc định phải nằm cuối danh sách.

Bài 2🟡 Vừa

Overload tính diện tích

Viết 2 hàm dienTich cùng tên: 1 tham số (hình vuông), 2 tham số (chữ nhật).

🖥️ Kết quả mẫu
Vuong canh 5: 25
CN 4x6: 24

💡 Trình biên dịch chọn hàm theo số tham số.

Bài 3🔴 Khó (sáng tạo)

Overload inThongTin

Viết 3 hàm inThongTin overload cho int, double, string.

🖥️ Kết quả mẫu
So nguyen: 5
So thuc: 3.14
Chuoi: Xin chao

💡 Khác kiểu tham số là overload hợp lệ.

BUỔI 8

Đệ quy (Recursion)

1 Hàm tự gọi chính nó

Đệ quy = hàm gọi lại chính nó, luôn cần điều kiện dừng (base case) để không lặp vô hạn:

📄 giaithua_dequy.cpp

      
Vẽ cây gọi hàm: giaiThua(3) → 3 * giaiThua(2) → 3 * 2 * giaiThua(1) — đi xuống tới base case rồi trả giá trị đi lên.

2 Đệ quy nhiều nhánh: Fibonacci

📄 fibonacci.cpp

      
Đệ quy dễ đọc hơn nhưng tốn bộ nhớ stack hơn vòng lặp. Với người mới: vẽ tay cây gọi trước khi chạy máy.
🏠 Bài tập về nhà

Buổi 8 — Đệ quy

Với mỗi bài, vẽ cây gọi hàm ra giấy trước. Làm 3 bài.

Bài 1🟢 Dễ

Tổng 1 → n đệ quy

Viết hàm đệ quy tong(int n) trả về 1 + 2 + … + n.

🖥️ Kết quả mẫu
tong(5) = 15

💡 Base: if (n == 0) return 0; · Đệ quy: n + tong(n-1).

Bài 2🟡 Vừa

Đếm số chữ số

Viết hàm đệ quy đếm số chữ số của một số nguyên dương.

🖥️ Kết quả mẫu
1234 co 4 chu so

💡 Base: n < 10 → 1 · Đệ quy: 1 + dem(n / 10).

Bài 3🔴 Khó (sáng tạo)

Lũy thừa a^b

Viết hàm đệ quy luyThua(int a, int b) = a mũ b. Vẽ cây gọi cho luyThua(2, 4).

🖥️ Kết quả mẫu
2^4 = 16

💡 Base: b == 0 → 1 · Đệ quy: a * luyThua(a, b-1).

BUỔI 9

Biến static + Review nhanh Hàm

1 Biến static trong hàm

📄 static_dem.cpp

      

💡 Ứng dụng: đếm số lần gọi, sinh ID tự tăng, máy đếm vé…

2 Review nhanh mạch Hàm (Buổi 0, 6, 7, 8)

Trước khi vào OOP, tự kiểm tra bằng 1 chương trình nhỏ dùng đủ:

Ví dụ: "máy tính đơn giản" — cộng/trừ overload cho int/double, trả 2 kết quả bằng tham chiếu, có 1 hàm đệ quy tính lũy thừa. Nếu còn lúng túng → ôn thêm hàm trước khi qua Class.
🏠 Bài tập về nhà

Buổi 9 — Biến static

Làm 3 bài.

Bài 1🟢 Dễ

Đếm số lần gọi

Viết hàm dùng static để đếm nó được gọi bao nhiêu lần, gọi 4 lần.

🖥️ Kết quả mẫu
Lan 1
Lan 2
Lan 3
Lan 4

💡 static int dem = 0; dem++;

Bài 2🟡 Vừa

Sinh ID tự tăng

Viết hàm capID() mỗi lần gọi trả về một ID tăng dần từ 1.

🖥️ Kết quả mẫu
ID = 1
ID = 2
ID = 3

💡 Trả về giá trị static sau khi tăng.

Bài 3🔴 Khó (sáng tạo)

Tổng hợp mạch Hàm

Viết 1 chương trình dùng đủ: 1 hàm overload + 1 hàm tham chiếu + 1 hàm đệ quy (ví dụ máy tính đơn giản).

🖥️ Yêu cầu
- overload cong(int) / cong(double)
- ham tham chieu tra 2 ket qua
- ham de quy luy thua

💡 Đây là "bài ôn" kết mạch Hàm trước khi vào OOP.

BUỔI 10

Nhập môn Lớp & Đối tượng (OOP)

1 OOP là gì & vì sao cần?

Lập trình thủ tục: dữ liệu và hàm xử lý tách rời. OOP gói dữ liệu + hàm vào cùng một chỗ gọi là lớp (class).

Liên hệ: string em dùng từ Buổi 1 thực chất là một class — có phương thức như .length(). Em đã dùng OOP từ đầu mà không biết!

2 Class đầu tiên: CDiem

📄 CDiem.cpp

      
🏠 Bài tập về nhà

Buổi 10 — Lớp & Đối tượng

Thuộc tính luôn private, tương tác qua phương thức. Làm 3 bài.

Bài 1🟢 Dễ

Class CDiem

Viết lại class CDiem (x, y private) với setXY, getX, getY, inToaDo.

🖥️ Kết quả mẫu
(3, 5)

💡 Nhớ private: cho x, y và public: cho phương thức.

Bài 2🟡 Vừa

Class CHocSinh

Viết class CHocSinh: tên, tuổi, điểm TB (private); có get/set và xepLoai() (≥8 Giỏi…).

🖥️ Kết quả mẫu
Bo - 8.5 - Gioi

💡 xepLoai() dùng if-else if trên điểm TB.

Bài 3🔴 Khó (sáng tạo)

Hoàn thiện & nhiều object

Thêm inThongTin() cho CHocSinh, tạo 2–3 object trong main và in thông tin từng bạn.

🖥️ Kết quả mẫu
An  - 15 - 7.0 - Kha
Bo  - 16 - 9.0 - Gioi

💡 Tạo nhiều object cùng class, gọi cùng phương thức.

BUỔI 11

Thực hành xây class hoàn chỉnh

1 Định nghĩa phương thức bên ngoài class

Khi class lớn, ta khai báo phương thức trong class và định nghĩa bên ngoài bằng toán tử phạm vi :: — giúp phần khai báo gọn, dễ đọc (cũng là bước đệm tách file .h/.cpp).

📄 CHinhChuNhat.cpp

      

💡 Cú pháp: KieuTraVe TenClass::tenPhuongThuc(...) { ... }. Thuộc tính luôn private trừ khi có lý do rõ ràng.

🏠 Bài tập về nhà

Buổi 11 — Class hoàn chỉnh

Bài 1🟢 Dễ

CHinhChuNhat đầy đủ

get/set, dienTich(), chuVi(). Định nghĩa phương thức ngoài class bằng ::.

🖥️ Mẫu
DT = 24, CV = 20

💡 CV = (dài + rộng) × 2.

Bài 2🟡 Vừa

CTaiKhoanNganHang

Số dư + chủ TK (private); napTien, rutTien (chặn rút quá số dư), xemSoDu.

🖥️ Mẫu
Nap 500 -> So du: 500
Rut 800 -> Khong du tien!

💡 rutTien kiểm tra if (tien > soDu).

Bài 3🔴 Khó

Nhiều tài khoản

Hoàn thiện, viết main tạo 2–3 tài khoản, thử nạp/rút và in số dư từng cái.

🖥️ Mẫu
An: 300
Bo: 1200

💡 Mỗi object là một tài khoản độc lập.

BUỔI 12

Constructor

1 Hàm khởi tạo (Constructor)

Object mới tạo có thuộc tính chưa khởi tạo (rác). Constructor là hàm đặc biệt trùng tên class, tự động chạy khi tạo object — dùng để gán giá trị ban đầu.

📄 constructor.cpp

      
🏠 Bài tập về nhà

Buổi 12 — Constructor

Bài 1🟢 Dễ

2 constructor cho CHocSinh

Thêm default constructor (gán rỗng/0) và constructor đầy đủ tham số.

🖥️ Mẫu
N/A - 0
Bo - 16

💡 Hai constructor trùng tên, khác tham số.

Bài 2🟡 Vừa

CDiem3D

Class điểm 3 chiều (x, y, z) với 2 constructor (mặc định & đầy đủ), hàm in.

🖥️ Mẫu
(0, 0, 0)
(1, 2, 3)

💡 Constructor mặc định gán tất cả = 0.

Bài 3🔴 Khó

Constructor + đối số mặc định

Viết class có 1 constructor dùng đối số mặc định để thay cho nhiều constructor.

🖥️ Mẫu
CSanPham("Sua") -> gia mac dinh 0
CSanPham("Banh", 15000)

💡 CSanPham(string ten, int gia = 0).

BUỔI 13

Destructor & cảnh báo shallow copy

1 Destructor & vòng đời object

Destructor ~TenClass() tự chạy khi object hết phạm vi hoặc bị delete. Nếu class có new bên trong → bắt buộc viết destructor để delete (liên hệ Buổi 4–5).

📄 CMangDong.cpp

      
Cảnh báo trước (sẽ sửa ở Buổi 19): nếu CMangDong b = a; rồi delete — mặc định C++ copy "từng byte" kể cả địa chỉ con trỏ → 2 object trỏ chung 1 vùng nhớ (shallow copy) → dễ crash. Cách sửa đúng (deep copy) học ở Buổi 19.
🏠 Bài tập về nhà

Buổi 13 — Destructor

Bài 1🟢 Dễ

In vòng đời object

Class có cout trong constructor và destructor để "nhìn thấy" lúc tạo/hủy.

🖥️ Mẫu
Tao object
Huy object

💡 Destructor: ~Ten() { cout << ...; }

Bài 2🟡 Vừa

Quan sát destructor tự chạy

Tạo vài object trong khối { }, quan sát destructor chạy khi ra khỏi khối.

🖥️ Mẫu
Tao A
Tao B
Huy B
Huy A

💡 Object hủy theo thứ tự ngược lúc tạo.

Bài 3🔴 Khó

Tái hiện shallow copy

Với CMangDong, copy 1 object rồi delete, truy cập cái còn lại để thấy lỗi. Ghi lại vì sao (chưa cần sửa — để Buổi 19).

🖥️ Yêu cầu
- Giai thich 2 object tro chung vung nho

💡 Đây là "hạt giống" cho copy constructor.

BUỔI 14

Kế thừa (Inheritance)

1 Quan hệ "là một loại của" (is-a)

Nhiều class chung thuộc tính/phương thức (vd CHocSinh, CGiaoVien đều có tên, tuổi). Kế thừa giúp tái sử dụng: class con thừa hưởng của class cha.

📄 ke_thua.cpp

      
🏠 Bài tập về nhà

Buổi 14 — Kế thừa

Bài 1🟢 Dễ

Class CNguoi

Tên, tuổi (protected) + gioiThieu().

🖥️ Mẫu
Toi la Bo, 16 tuoi

💡 Đây là class cha dùng lại ở các bài sau.

Bài 2🟡 Vừa

CHocSinh kế thừa

CHocSinh : public CNguoi thêm điểm TB + phương thức riêng, constructor gọi cha.

🖥️ Mẫu
Toi la An, 15 tuoi
Diem TB: 8.0

💡 : CNguoi(ten, tuoi).

Bài 3🔴 Khó

CGiaoVien

Thêm CGiaoVien : public CNguoi với môn dạy, constructor gọi đúng constructor cha.

🖥️ Mẫu
Toi la Cô Lan, day Toan

💡 Cùng một cha, hai class con khác nhau.

BUỔI 15

Đa hình & Trừu tượng

1 Hàm ảo (virtual) & lớp trừu tượng

Con trỏ cha trỏ tới object con, gọi phương thức trùng tên → mặc định gọi bản của cha (sai ý muốn). Thêm virtual → C++ gọi đúng bản của object thực sự đang được trỏ tới. Đó là đa hình.

📄 da_hinh.cpp

      
🏠 Bài tập về nhà

Buổi 15 — Đa hình & Trừu tượng

Bài 1🟢 Dễ

Thêm virtual

Từ CNguoi/CHocSinh, thêm virtual gioiThieu() và override ở con.

🖥️ Mẫu
Toi la hoc sinh

💡 Bỏ virtual thử xem output sai thế nào.

Bài 2🟡 Vừa

Mảng con trỏ cha

Tạo mảng CNguoi* chứa cả CHocSinh & CGiaoVien, duyệt gọi gioiThieu().

🖥️ Mẫu
Toi la hoc sinh
Toi la giao vien

💡 Đây là "đa hình" thực tế.

Bài 3🔴 Khó

Lớp trừu tượng CHinh

CHinh abstract với tinhDienTich()=0; CHinhTron, CHinhVuong hiện thực riêng; tính tổng diện tích qua mảng con trỏ.

🖥️ Mẫu
Tong dien tich = 78.5

💡 Không tạo được object của CHinh trực tiếp.

BUỔI 16 · 🏁 CHECKPOINT

Tổng hợp 4 tính chất OOP

🏁 Mốc quan trọng NHẤT toàn khóa

Xác nhận nắm vững cả 4 tính chất: Đóng gói · Kế thừa · Đa hình · Trừu tượng. Nếu chưa vững, chèn buổi phụ đạo trước khi sang Giai đoạn 2 — đây là chỗ đáng "hy sinh" tiến độ nhất.

📄 quan_ly_nhan_vien.cpp (demo)

      
Tiêu chí qua buổi: tự chỉ ra & giải thích đúng cả 4 tính chất trong code của chính mình, không cần gợi ý thuật ngữ.
🎯 Bài kiểm tra

Buổi 16 — Checkpoint OOP

Mức 1🟢 Dễ

Lớp cha trừu tượng + 2 con

Thiết kế CNhanVien trừu tượng với tinhLuong()=0, 2 class con hiện thực khác nhau.

🖥️ Mẫu
Chinh thuc: 10000000
Thoi vu: 5000000

💡 Đủ: trừu tượng + kế thừa.

Mức 2🟡 Vừa

Đa hình qua mảng con trỏ

Dùng mảng CNhanVien* quản lý, gọi tinhLuong() đa hình, cộng tổng lương.

🖥️ Mẫu
Tong luong = 15000000

💡 Đủ: đa hình + đóng gói (thuộc tính private).

Mức 3🔴 Khó

Tự giải thích 4 tính chất

Hoàn thiện hệ thống (constructor/destructor hợp lý) và tự viết 4 câu chỉ ra mỗi tính chất nằm ở đâu trong code.

🖥️ Yêu cầu
- Dong goi: ...
- Ke thua: ...
- Da hinh: ...
- Truu tuong: ...

💡 Đây là mục tiêu cốt lõi của cả khóa!

BUỔI 17

Linked List — khởi tạo & duyệt

1 Node dạng class + duyệt danh sách

Mảng có kích thước cố định; danh sách liên kết nối các Node (dữ liệu + con trỏ pNext) bằng con trỏ — kết hợp con trỏ (Giai đoạn 1) + class (Buổi 10–16).

📄 linked_list.cpp

      

💡 Node có constructor tự gán pNext = NULL — áp dụng lại Constructor (Buổi 12) vào bài toán mới. Duyệt: while (p != NULL) { ...; p = p->pNext; }.

🏠 Bài tập về nhà

Buổi 17 — Linked List (khởi tạo)

Bài 1🟢 Dễ

Nối tay & in

Xây class Node, tạo 3–4 Node nối tay, viết inDanhSach().

🖥️ Mẫu
10 -> 20 -> 30 -> NULL

💡 Node constructor gán pNext = NULL.

Bài 2🟡 Vừa

themCuoi()

Viết hàm themCuoi(x) tổng quát để thêm phần tử vào cuối danh sách.

🖥️ Mẫu
Sau them 40: 10 20 30 40

💡 Đi tới Node cuối (pNext == NULL) rồi nối.

Bài 3🔴 Khó

Đếm & tìm kiếm

Viết hàm đếm số phần tử và hàm kiểm tra một giá trị có tồn tại không. Áp dụng: danh sách tên 5 học sinh.

🖥️ Mẫu
So phan tu: 5
Tim 'An': co

💡 Duyệt danh sách, đếm/so sánh.

BUỔI 18

Linked List — thêm & xóa

1 Thêm đầu, xóa Node

Phần khó nhất vì nhiều trường hợp đặc biệt. Thứ tự các dòng lệnh rất quan trọng — đổi pStart trước sẽ mất liên kết!

📄 them_dau.cpp

      
🏠 Bài tập về nhà

Buổi 18 — Linked List (thêm/xóa)

Bài 1🟢 Dễ

themDau()

Cài đặt themDau(x) đúng thứ tự, test bằng cách thêm 1,2,3.

🖥️ Mẫu
1 2 3

💡 Nối pNext trước, cập nhật pStart sau.

Bài 2🟡 Vừa

xoaDau & xoaTheoGiaTri

Cài xoaDau()xoaTheoGiaTri(x), nhớ delete Node bị gỡ.

🖥️ Mẫu
Sau xoa 2: 1 3

💡 Cần con trỏ "trước" điểm xóa.

Bài 3🔴 Khó

xoaToanBo + quản lý SV

xoaToanBo() giải phóng hết Node; áp dụng quản lý danh sách sinh viên (thêm/xóa theo tên/in/TB).

🖥️ Mẫu
Da giai phong toan bo

💡 Duyệt và delete từng Node.

BUỔI 19

this + Copy Constructor & Friend

1 this & Copy Constructor (deep copy)

Con trỏ this trỏ tới chính object đang gọi — dùng để phân biệt tham số trùng tên thuộc tính. Copy Constructor sửa triệt để cạm bẫy shallow copy (Buổi 13): cấp phát vùng nhớ MỚI thay vì dùng chung.

📄 copy_ctor.cpp

      
🏠 Bài tập về nhà

Buổi 19 — this & Copy Constructor

Bài 1🟢 Dễ

Dùng this->

Viết constructor có tham số trùng tên thuộc tính, dùng this-> để phân biệt.

🖥️ Mẫu
ten = Bo, tuoi = 16

💡 this->ten = ten;

Bài 2🟡 Vừa

Copy constructor deep copy

Cho một class có con trỏ thành viên, viết copy constructor cấp phát vùng nhớ mới.

🖥️ Mẫu
a: 0 1 2
b (copy): 0 1 2  (vung nho rieng)

💡 a = new int[n]; rồi copy từng phần tử.

Bài 3🔴 Khó

Friend function

Viết hàm friend soSanh(a, b) so sánh 2 object CHocSinh theo điểm (truy cập private).

🖥️ Mẫu
An (8.0) < Bo (9.0)

💡 Khai báo friend bên trong class.

BUỔI 20

Nạp chồng toán tử

1 Overload cho toán tử (+, <<)

Overload không chỉ cho hàm (Buổi 7) mà cả toán tử: cho phép viết a + b, cout << a với object của mình.

📄 CPhanSo.cpp

      
🏠 Bài tập về nhà

Buổi 20 — Nạp chồng toán tử

Bài 1🟢 Dễ

operator+ cho CPhanSo

Overload + để cộng 2 phân số.

🖥️ Mẫu
1/2 + 1/3 = 5/6

💡 tu*b.mau + b.tu*mau / mau*b.mau.

Bài 2🟡 Vừa

operator- và operator==

Thêm phép trừ và so sánh bằng cho CPhanSo.

🖥️ Mẫu
1/2 == 2/4 -> dung

💡 So sánh bằng cách nhân chéo.

Bài 3🔴 Khó

operator<< bằng friend

Overload << (in dạng "tử/mẫu") bằng friend, hoàn thiện + - * == <<.

🖥️ Mẫu
cout << a; -> 5/6

💡 friend ostream& operator<<(ostream&, const CPhanSo&).

BUỔI 21

Xử lý ngoại lệ (Exception)

1 try / catch / throw

Lỗi runtime (chia 0, ngoài mảng, cấp phát thất bại) nếu không xử lý sẽ crash. C++ cho phép ném lỗi (throw) và bắt lỗi (try/catch) có kiểm soát:

📄 exception.cpp

      
🏠 Bài tập về nhà

Buổi 21 — Ngoại lệ

Bài 1🟢 Dễ

Chia có kiểm soát

Hàm chia(a, b) throw khi b == 0, bắt bằng try/catch.

🖥️ Mẫu
10/2 = 5
5/0 -> Loi: chia cho 0

💡 throw "..." rồi catch(const char*).

Bài 2🟡 Vừa

Nhiều catch

Chương trình có nhiều khối catch khác kiểu + catch(...).

🖥️ Mẫu
Bat duoc loi so
Bat duoc loi khac

💡 Thứ tự catch từ cụ thể → tổng quát.

Bài 3🔴 Khó

Custom Exception

NgoaiLeChiaCho0 : public exception override what(); áp dụng cho máy tính / rút quá số dư (CTaiKhoanNganHang).

🖥️ Mẫu
Loi: Rut qua so du!

💡 Bắt bằng catch(exception &e) { e.what(); }.

BUỔI 22 · 🎓

Ôn tập toàn khóa + Dự án tổng hợp

🎓 Sản phẩm hoàn chỉnh — chuẩn bị thi & đồ án

Tổng hợp tất cả thành 1 dự án nhỏ. Ví dụ "Quản lý thư viện": TaiLieu trừu tượng, con là Sach/TapChi, danh sách bằng linked list, overload <<, exception khi mượn sách hết.

📄 du_an_min.cpp (khung)

      
Ưu tiên dùng đề đồ án thật của trường nếu đã có. Nhìn lại toàn bộ 23 buổi, chỉ ra mạnh/yếu ở đâu, luyện đề mẫu của trường.
🎓 Đề dự án cuối khóa

Buổi 22 — Dự án tổng hợp

Bắt buộc dùng tối thiểu: 1 class cha trừu tượng + 2 con, constructor/destructor hợp lý, ≥ 1 toán tử overload, xử lý ≥ 1 ngoại lệ.

Mức 1🟢 Dễ

Khung OOP

Class cha trừu tượng + 2 class con override, đầy đủ constructor/destructor.

🖥️ Mẫu
Sach: Lap trinh C++
Tap chi: Khoa hoc

💡 Nền tảng: trừu tượng + kế thừa + đa hình.

Mức 2🟡 Vừa

Danh sách + overload

Quản lý các đối tượng bằng linked list (hoặc mảng con trỏ), thêm 1 toán tử overload (vd <<).

🖥️ Mẫu
[Danh sach tai lieu]
1. Sach: ...
2. Tap chi: ...

💡 Kết hợp Buổi 17–18 + Buổi 20.

Mức 3🔴 Khó

Hoàn chỉnh + exception

Thêm xử lý ngoại lệ (vd mượn tài liệu đã hết), menu tương tác, hoàn thiện thành sản phẩm nộp được.

🖥️ Mẫu
Muon 'Sach X' -> Loi: Da het!

💡 Đây là "bản demo" cho đồ án PRG1006 thật.

🎉 Trọn bộ 23 buổi

Đã đủ Buổi 0 → 22: Hàm, C++, Con trỏ, Cấp phát động, Tham chiếu, Overload, Đệ quy, static, Class, Constructor/Destructor, Kế thừa, Đa hình, Linked List, this & Copy Constructor, Nạp chồng toán tử, Ngoại lệ và Dự án tổng hợp. Chúc con học tốt! 🚀

← Quay lại khóa C căn bản