Hàm tổng 1 → n
Viết hàm tong(int n) trả về tổng các số từ 1 đến n.
tong(5) = 15
💡 Dùng vòng lặp cộng dồn rồi return.
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.
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:
main, định nghĩa đầy đủ sau — hoặc viết hàm trên main luôn nếu chương trình nhỏ.return trả về 1 giá trị, hoặc void nếu không trả gì.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":
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ỏ) và Buổi 6 (tham chiếu) sẽ trả lời.
💡 Ư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.
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.
Hàm tổng 1 → n
Viết hàm tong(int n) trả về tổng các số từ 1 đến n.
tong(5) = 15
💡 Dùng vòng lặp cộng dồn rồi return.
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ử.
Mang: 4 6 8 2 Trung binh = 5.00
💡 Tổng là int, chia dùng ép kiểu (float)tong / n.
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ố.
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).
cin & coutC++ = 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:
#include <iostream> — thư viện nhập/xuất của C++.using namespace std; — để viết cout thay vì std::cout.cout << ... in ra; cin >> ... nhập vào; endl xuống dòng.using namespace std; → báo lỗi cout was not declared.bool & stringbool: chỉ nhận true / false — rõ nghĩa hơn dùng int 0/1 như C.string: chuỗi "xịn" của C++, không cần mảng char + '\0'; khai báo string ten; và nhập bằng cin.Chuyển tư duy sang cin/cout. Làm 3 bài, in ra giống mẫu.
Lời chào
Nhập tên (string), in ra "Xin chao <ten>!" bằng cout.
Nhap ten: Bo Xin chao Bo!
💡 string ten; cin >> ten;
Máy tính 2 số
Nhập 2 số thực, in tổng, hiệu, tích, thương bằng cout.
a = 6, b = 4 Tong = 10 Hieu = 2 Tich = 24 Thuong = 1.5
💡 Dùng double cho phép chia ra số lẻ.
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++).
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.
Mỗi biến là một ô nhớ có địa chỉ. Con trỏ là biến chứa địa chỉ của một biến khác.
& (địa chỉ) và * (truy xuất)&a — lấy địa chỉ của biến a.int *p = &a; — khai báo con trỏ p trỏ tới a.*p — truy xuất giá trị mà p đang trỏ tới (đọc hoặc ghi).* có 2 nghĩa: lúc khai báo (int *p) và lúc dùng (*p) — chỗ hay lú nhất!*p gây crash. Rất nguy hiểm!int *p = NULL; (hoặc nullptr) khi chưa trỏ tới đâu.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:
Vẽ sơ đồ bộ nhớ ra giấy trước khi code. Làm 3 bài.
Đọc qua con trỏ
Khai báo int a = 25;, cho con trỏ p trỏ tới a, in giá trị a qua *p.
Gia tri qua con tro: 25
💡 int *p = &a; cout << *p;
Ghi qua con trỏ
Dùng con trỏ để đổi giá trị của biến a, in a trước và sau khi đổi.
Truoc: a = 25 Sau: a = 99
💡 *p = 99; sẽ sửa chính biến a.
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.
Truoc: x = 3, y = 7 Sau: x = 7, y = 3
💡 Gọi hàm bằng swap(&x, &y); — nhớ dấu &.
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ứ.
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ớ:
💡 *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.
&a[i]) để thấy bước nhảy đúng bằng sizeof(int).Làm 3 bài. Bài khó chuẩn bị cho Buổi 6 (con trỏ đôi trong hàm).
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ử.
5 10 15 20
💡 int *p = a; rồi lặp in *(p + i).
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.
a[0] tai 0x100 a[1] tai 0x104 a[2] tai 0x108
💡 In &a[i] (hoặc a + i).
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.
Truoc: *p = 5 Sau: *p = 100
💡 Truyền &p vào hàm; bên trong dùng **pp = 100;
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.
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.
new int / new int[n] — xin 1 biến / 1 mảng động (thay cho malloc của C).delete p / delete[] a — trả lại bộ nhớ.new phải có đúng một delete tương ứng — quên là rò rỉ bộ nhớ (memory leak).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.
Nhớ: mỗi new một delete. Làm 3 bài.
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[].
Nhap n: 3 Nhap: 5 8 2 Mang: 5 8 2
💡 int *a = new int[n]; … delete[] 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.
n = 4, mang: 4 6 8 2 Tong = 20, TB = 5.00
💡 Dùng double cho trung bình. Nhớ delete[] cuối.
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.
- Chi ra dong bi leak - Them delete[] dung cho
💡 Tìm new nào chưa có delete tương ứng.
Đây là mốc quan trọng. Nếu chưa vững con trỏ / new–delete, lặp lại buổi này trước khi đi tiếp, đừng vội sang Buổi 6.
delete thì p còn dùng được không?"new/delete thay vì mảng tĩnh.new/delete.Làm dần theo 3 mức. Đây là "đề" củng cố toàn bộ con trỏ & heap.
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.
So diem: 3 Diem: 8 7 9
💡 Dựng khung new → nhập → in → delete[].
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.
TB = 8.00 Max = 9, Min = 7
💡 Khởi tạo max = min = a[0] rồi duyệt.
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.
- 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 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ỏ:
| Cách truyền | Sửa được biến gốc? | Cú pháp gọi |
|---|---|---|
| Giá trị | ❌ Không | swap(x, y) |
| Con trỏ | ✅ Có | swap(&x, &y) |
| Tham chiếu | ✅ Có (gọn nhất) | swap(x, y) |
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):
Chọn đúng cách truyền tham số cho từng bài. Làm 3 bài.
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).
x = 7, y = 3
💡 Gọn hơn con trỏ — không cần dấu & khi gọi.
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).
Truoc: 1 2 3 Sau: 2 4 6
💡 void nhanDoi(int a[], int n).
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.
a = 3, b = 4 Tong = 7, Tich = 12
💡 void tinh(int a, int b, int &tong, int &tich).
Cho tham số một giá trị sẵn — khi gọi không truyền thì dùng giá trị đó:
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:
Làm 3 bài.
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.
Xin chao, Bo! Hello, An!
💡 Tham số mặc định phải nằm cuối danh sách.
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).
Vuong canh 5: 25 CN 4x6: 24
💡 Trình biên dịch chọn hàm theo số tham số.
Overload inThongTin
Viết 3 hàm inThongTin overload cho int, double, string.
So nguyen: 5 So thuc: 3.14 Chuoi: Xin chao
💡 Khác kiểu tham số là overload hợp lệ.
Đệ 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(3) → 3 * giaiThua(2) → 3 * 2 * giaiThua(1) — đi xuống tới base case rồi trả giá trị đi lên.
Với mỗi bài, vẽ cây gọi hàm ra giấy trước. Làm 3 bài.
Tổng 1 → n đệ quy
Viết hàm đệ quy tong(int n) trả về 1 + 2 + … + n.
tong(5) = 15
💡 Base: if (n == 0) return 0; · Đệ quy: n + tong(n-1).
Đếm số chữ số
Viết hàm đệ quy đếm số chữ số của một số nguyên dương.
1234 co 4 chu so
💡 Base: n < 10 → 1 · Đệ quy: 1 + dem(n / 10).
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).
2^4 = 16
💡 Base: b == 0 → 1 · Đệ quy: a * luyThua(a, b-1).
static trong hàmstatic: chỉ khởi tạo một lần, giữ giá trị giữa các lần gọi hàm.💡 Ứng dụng: đếm số lần gọi, sinh ID tự tăng, máy đếm vé…
Trước khi vào OOP, tự kiểm tra bằng 1 chương trình nhỏ dùng đủ:
Làm 3 bài.
Đế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.
Lan 1 Lan 2 Lan 3 Lan 4
💡 static int dem = 0; dem++;
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.
ID = 1 ID = 2 ID = 3
💡 Trả về giá trị static sau khi tăng.
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).
- 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.
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).
private / public — đóng gói (encapsulation): giấu dữ liệu, chỉ cho truy cập qua phương thức.. — d.inToaDo();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!
CDiemprivate: int x, y; — dữ liệu được giấu, bên ngoài không sửa trực tiếp.public: các phương thức setXY, inToaDo để tương tác.CDiem d; tạo object; d.setXY(3, 5); gọi phương thức.Thuộc tính luôn private, tương tác qua phương thức. Làm 3 bài.
Class CDiem
Viết lại class CDiem (x, y private) với setXY, getX, getY, inToaDo.
(3, 5)
💡 Nhớ private: cho x, y và public: cho phương thức.
Class CHocSinh
Viết class CHocSinh: tên, tuổi, điểm TB (private); có get/set và xepLoai() (≥8 Giỏi…).
Bo - 8.5 - Gioi
💡 xepLoai() dùng if-else if trên điểm TB.
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.
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.
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).
💡 Cú pháp: KieuTraVe TenClass::tenPhuongThuc(...) { ... }. Thuộc tính luôn private trừ khi có lý do rõ ràng.
CHinhChuNhat đầy đủ
get/set, dienTich(), chuVi(). Định nghĩa phương thức ngoài class bằng ::.
DT = 24, CV = 20
💡 CV = (dài + rộng) × 2.
CTaiKhoanNganHang
Số dư + chủ TK (private); napTien, rutTien (chặn rút quá số dư), xemSoDu.
Nap 500 -> So du: 500 Rut 800 -> Khong du tien!
💡 rutTien kiểm tra if (tien > soDu).
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.
An: 300 Bo: 1200
💡 Mỗi object là một tài khoản độc lập.
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.
2 constructor cho CHocSinh
Thêm default constructor (gán rỗng/0) và constructor đầy đủ tham số.
N/A - 0 Bo - 16
💡 Hai constructor trùng tên, khác tham số.
CDiem3D
Class điểm 3 chiều (x, y, z) với 2 constructor (mặc định & đầy đủ), hàm in.
(0, 0, 0) (1, 2, 3)
💡 Constructor mặc định gán tất cả = 0.
Constructor + đối số mặc định
Viết class có 1 constructor dùng đối số mặc định để thay cho nhiều constructor.
CSanPham("Sua") -> gia mac dinh 0
CSanPham("Banh", 15000)💡 CSanPham(string ten, int gia = 0).
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 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.
In vòng đời object
Class có cout trong constructor và destructor để "nhìn thấy" lúc tạo/hủy.
Tao object Huy object
💡 Destructor: ~Ten() { cout << ...; }
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.
Tao A Tao B Huy B Huy A
💡 Object hủy theo thứ tự ngược lúc tạo.
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).
- Giai thich 2 object tro chung vung nho
💡 Đây là "hạt giống" cho copy constructor.
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.
class CHocSinh : public CNguoi { ... }.protected: class con thấy được, bên ngoài thì không.CHocSinh(...) : CNguoi(ten) { ... }.Class CNguoi
Tên, tuổi (protected) + gioiThieu().
Toi la Bo, 16 tuoi
💡 Đây là class cha dùng lại ở các bài sau.
CHocSinh kế thừa
CHocSinh : public CNguoi thêm điểm TB + phương thức riêng, constructor gọi cha.
Toi la An, 15 tuoi Diem TB: 8.0
💡 : CNguoi(ten, tuoi).
CGiaoVien
Thêm CGiaoVien : public CNguoi với môn dạy, constructor gọi đúng constructor cha.
Toi la Cô Lan, day Toan
💡 Cùng một cha, hai class con khác nhau.
virtual) & lớp trừu tượngCon 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.
virtual void ve() = 0; → lớp trừu tượng (abstract) không tạo object trực tiếp được, chỉ làm cha.Thêm virtual
Từ CNguoi/CHocSinh, thêm virtual gioiThieu() và override ở con.
Toi la hoc sinh
💡 Bỏ virtual thử xem output sai thế nào.
Mảng con trỏ cha
Tạo mảng CNguoi* chứa cả CHocSinh & CGiaoVien, duyệt gọi gioiThieu().
Toi la hoc sinh Toi la giao vien
💡 Đây là "đa hình" thực tế.
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ỏ.
Tong dien tich = 78.5
💡 Không tạo được object của CHinh trực tiếp.
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.
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.
Chinh thuc: 10000000 Thoi vu: 5000000
💡 Đủ: trừu tượng + kế thừ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.
Tong luong = 15000000
💡 Đủ: đa hình + đóng gói (thuộc tính private).
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.
- Dong goi: ... - Ke thua: ... - Da hinh: ... - Truu tuong: ...
💡 Đây là mục tiêu cốt lõi của cả khóa!
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).
💡 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; }.
Nối tay & in
Xây class Node, tạo 3–4 Node nối tay, viết inDanhSach().
10 -> 20 -> 30 -> NULL
💡 Node constructor gán pNext = NULL.
themCuoi()
Viết hàm themCuoi(x) tổng quát để thêm phần tử vào cuối danh sách.
Sau them 40: 10 20 30 40
💡 Đi tới Node cuối (pNext == NULL) rồi nối.
Đế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.
So phan tu: 5 Tim 'An': co
💡 Duyệt danh sách, đếm/so sánh.
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!
node->pNext = pStart; trước, rồi mới pStart = node;delete Node bị gỡ (liên hệ Buổi 4–5).themDau()
Cài đặt themDau(x) đúng thứ tự, test bằng cách thêm 1,2,3.
1 2 3
💡 Nối pNext trước, cập nhật pStart sau.
xoaDau & xoaTheoGiaTri
Cài xoaDau() và xoaTheoGiaTri(x), nhớ delete Node bị gỡ.
Sau xoa 2: 1 3
💡 Cần con trỏ "trước" điểm xóa.
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).
Da giai phong toan bo
💡 Duyệt và delete từng Node.
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.
this->n = n; — this phân biệt thuộc tính với tham số cùng tên.CMang b = a;, truyền/trả object theo giá trị.private.Dùng this->
Viết constructor có tham số trùng tên thuộc tính, dùng this-> để phân biệt.
ten = Bo, tuoi = 16
💡 this->ten = ten;
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.
a: 0 1 2 b (copy): 0 1 2 (vung nho rieng)
💡 a = new int[n]; rồi copy từng phần tử.
Friend function
Viết hàm friend soSanh(a, b) so sánh 2 object CHocSinh theo điểm (truy cập private).
An (8.0) < Bo (9.0)
💡 Khai báo friend bên trong class.
+, <<)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.
const CPhanSo &: dùng tham chiếu để khỏi copy, const để không lỡ sửa.cout << a có toán hạng trái là ostream → phải overload << dạng friend (không phải thành viên). Dùng lại friend từ Buổi 19.operator+ cho CPhanSo
Overload + để cộng 2 phân số.
1/2 + 1/3 = 5/6
💡 tu*b.mau + b.tu*mau / mau*b.mau.
operator- và operator==
Thêm phép trừ và so sánh bằng cho CPhanSo.
1/2 == 2/4 -> dung
💡 So sánh bằng cách nhân chéo.
operator<< bằng friend
Overload << (in dạng "tử/mẫu") bằng friend, hoàn thiện + - * == <<.
cout << a; -> 5/6
💡 friend ostream& operator<<(ostream&, const CPhanSo&).
try / catch / throwLỗ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:
catch cho nhiều kiểu lỗi; catch(...) bắt tất cả.exception, override what() — bắt bằng catch(exception &e) nhờ đa hình (Buổi 15). Đây chính là ứng dụng thực tế của virtual!Chia có kiểm soát
Hàm chia(a, b) throw khi b == 0, bắt bằng try/catch.
10/2 = 5 5/0 -> Loi: chia cho 0
💡 throw "..." rồi catch(const char*).
Nhiều catch
Chương trình có nhiều khối catch khác kiểu + catch(...).
Bat duoc loi so Bat duoc loi khac
💡 Thứ tự catch từ cụ thể → tổng quát.
Custom Exception
NgoaiLeChiaCho0 : public exception override what(); áp dụng cho máy tính / rút quá số dư (CTaiKhoanNganHang).
Loi: Rut qua so du!
💡 Bắt bằng catch(exception &e) { e.what(); }.
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.
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ệ.
Khung OOP
Class cha trừu tượng + 2 class con override, đầy đủ constructor/destructor.
Sach: Lap trinh C++ Tap chi: Khoa hoc
💡 Nền tảng: trừu tượng + kế thừa + đa hình.
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 <<).
[Danh sach tai lieu] 1. Sach: ... 2. Tap chi: ...
💡 Kết hợp Buổi 17–18 + Buổi 20.
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.
Muon 'Sach X' -> Loi: Da het!
💡 Đây là "bản demo" cho đồ án PRG1006 thật.
Đã đủ 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! 🚀