lO MoARcPSD| 45467232
i s 1: Tng quan lp trình hướng đi tượng
1. Trc nghiệm (2 đim)
a. Li ích chính ca OOP gì?
A. Tăng hiu ng chương trình
B. Gim s dòng lnh
C. ng nh mô-đun, bo trì và i s dng D. Không cn viết hàm
b. Câu lnh o ng đ to đối tượng t lp trong C++?
A. class a = new A();
B. A a;
C. A = new object();
D. object A = new A();
2. T luận (3 đim)
Trình y đặc đim ca lp trình hướng đi tượng và so sánh vi lp trình cu trúc.
3. Lập trình (5 điểm)
Viết chương trình định nghĩa lớp SinhVien gm: mã SV, n SV, điểm KTLT. Nhp danh sách
sinh vn và in danh sách ra màn hình.
i s 2: Kế tha và nh trừu tượng trong C++
1. Trc nghiệm (2 đim)
a. Trong kế tha, t ka nào giúp lp con kế tha công khai lp cha?
A. inherit
B. extends
C. public
D. private
b. Tính trừu tượng th hin nht qua đâu?
A. Hàm thành vn nh
B. Hàm o
C. Lp trừu tượng (abstract class)
D. Giao din
2. T luận (3 đim)
Trình y vai trò canh trừu tượng trong thiết kế phn mm. So sánh lp trừu tượng và lp
giao din.
3. Lập trình (5 điểm)
Xây dng lp trừu tượng NhanVien vi m o tinhLuong(). Hai lp con:
- NVCongNhat: lương = s ngày * 300k
- NVSanPham: lương = s sn phm * 200k
Viết chương trình cnh quản danh sách nhân vn.
lO MoARcPSD|45467232
i s 3: Đanh và mo
1. Trc nghiệm (2 đim)
a. Hàm o thuần y được khai o như thế nào?
A. virtual void func();
B. void func() = 0;
C. virtual void func() = 0;
D. abstract func();
b. Đa hình động được thc hin qua?
A. Hàm main
B. Hàm to
C. Hàm o và con tr lp cha
D. Kế tha nhiu lp
2. T luận (3 đim)
Phân biệt đa hình nh và đa hình động. Ưu nhược điểm ca mi loi.
3. Lập trình (5 điểm)
To lp Cha có hàm o tinhTien(). Hai lp con:
- ThanhToanTienMat
- ThanhToanChuyenKhoan
Ghi đèm tinhTien với chiết khu khác nhau. Viết chương trình quản gi m bng con
tr lp cha.
i s 4: Qun lý b nh và con tr trong OOP
1. Trc nghiệm (2 đim)
a. Trong C++, t ka o được dùng để cp phát động b nh?
A. malloc
B. alloc
C. new
D. pointer
b. Khi o cn dùng destructor?
A. Khi tạo đối tượng
B. Gán đối tượng
C. Gii phóng i nguyên
D. Sa d liu
2. T luận (3 đim)
lO MoARcPSD|45467232
Gii thích s kc bit gia constructor, destructor khi o dùng cấp phát động (dynamic
allocation).
3. Lập trình (5 điểm)
Viết chương trình quản sinh vn vi mng cp pt động. Lp SinhVien gm: n, đim TB.
Nhp N sinh viên và xut danh sách.
i s 5: Mô nh a h thng bng lớp và đối tượng 1.
Trc nghiệm (2 đim)
a. UML ?
A. Nn ng lập trình hướng đối tượng B. Công c pn ch d liu
C. Nn ng mô nh hóa hướng đối tượng D. Mt IDE
b. Quan h "has-a" trong OOP th hin qua?
A. Kế tha
B. Giao din
C. Thành phn lớp đối tượng lp khác
D. nh đa nh
2. T luận (3 đim)
Trình y các quan h gia các lp trong UML: kế tha, kết hp, tp hp.
3. Lập trình (5 điểm)
Thiết kế h thng qun thư viện gm các lp:
- Sach: mã sách, n sách
- NhaXuatBan: tên NXB, m thành lập
- Mỗi sách 1 NXB → dùng quan hệ "has-a"
Nhp danh sách sách in thông tin ra màn nh.
Gii
i s 1: Tng quan lập trình hướng đối tượng
1. Trc nghim:
a. C → ng nh mô-đun, bo trì và i s dng
b. B A a;
2. T lun:
Đặc điểm ca lp trình hướng đối tượng (OOP):
Đóng gói (Encapsulation)
Kế tha (Inheritance)
Đa nh (Polymorphism)
Trừu tượnga (Abstraction)
lO MoARcPSD|45467232
3. Lp trình:
#include <iostream> using
namespace std;
class SinhVien { private:
string maSV, tenSV;
float diemKTLT; public:
void nhap() { cout << "Ma SV: "; cin
>> maSV; cin.ignore(); cout <<
"Ten SV: "; getline(cin, tenSV); cout <<
"Diem KTLT: "; cin >> diemKTLT;
}
void xuat() { cout << "Ma: " << maSV << ", Ten: " << tenSV << ", Diem: " <<
diemKTLT << endl;
}
};
int main() {
int n;
cout << "Nhap so SV: "; cin >> n;
SinhVien* ds = new SinhVien[n]; for (int i =
0; i < n; i++) { cout << "\nNhap SV thu "
<< i + 1 << ":\n"; ds[i].nhap();
}
lO MoARcPSD|45467232
cout << "\nDanh sach sinh vien:\n";
for (int i = 0; i < n; i++) {
ds[i].xuat();
}
delete[] ds;
return 0;
}
i s 2: Kế tha và nh trừu tượng
1. Trc nghim:
a. C → public
b. C → Lp trừu tưng (abstract class)
2. T lun:
Vai trò ca trừu tượng:
n chi tiết cài đặt
Gp thiết kế h thng linh hot, d m rng
-Đơn giản a độ phc tp:nh trừu tượng giúp ẩn đi các chi tiết trin khai phc tp n
trong, ch hin th nhng thông tin và chức năng cn thiết cho người s dng. Điu này giúp
ngưi lp trình tp trung vào "cái " mà không cần quanm đến "như thế o".
-ngnh mô-đun hóa: Bằng cách định nga các giao diện trừu tượng, chúng ta có th chia h
thng thành các module độc lp. Mi module có th đưc phát trin và kim th riêng bit, sau
đó ch hợp li vi nhau.
-D bo trì và m rng: Khi các chi tiết triển khai được ẩn đi, việc thay đổi hoc nâng cp mt
phn ca h thng s ít ảnh hưởng đến các phn kc, gp gim thiu ri ro và chi p bo trì.
Đồng thi, vic thêm các chức năng mới cũng dễ dàng hơn.
-Thúc đyi s dng mã: Các lp trừu tượng hoc giao diện định nga mt khn mu
chung, cho pp các lp con trin khai theo cách riêng của mình nhưng vẫn tuân th mt cu
trúc nht đnh. Điềuy thúc đẩy vic tái s dng mã và gim s trùng lp.
-To ra mt kiến trúc ng: Tính trừu tượng giúp định nga các tng (layers) và thành phn
(components) trong kiến trúc phn mm mt cách ràng, d hiu và d qun.
lO MoARcPSD|45467232
3. Lp trình:
#include <iostream> using
namespace std;
class NhanVien { public:
virtual float tinhLuong() = 0;
virtual void nhap() = 0;
virtual void xuat() = 0; virtual
~NhanVien() {}
};
class NVCongNhat : public NhanVien { private:
int soNgay; public:
void nhap() {
cout << "Nhap so ngay lam: "; cin >> soNgay;
}
lO MoARcPSD|45467232
float tinhLuong() override {
return soNgay * 300000;
}
void xuat() { cout << "NVCongNhat - Luong: " <<
tinhLuong() << endl;
}
};
class NVSanPham : public NhanVien { private:
int soSP; public:
void nhap() { cout << "Nhap so san
pham: "; cin >> soSP;
}
float tinhLuong() override {
return soSP * 200000;
}
void xuat() { cout << "NVSanPham - Luong: " <<
tinhLuong() << endl;
}
};
int main() {
int n;
cout << "Nhap so NV: "; cin >> n;
NhanVien* ds[100];
for (int i = 0; i < n; i++)
{ int loai;
cout << "\nNhan vien thu " << i + 1 << " (1-Cong Nhat, 2-San Pham): "; cin >> loai;
if (loai == 1) ds[i] = new NVCongNhat; else ds[i] = new NVSanPham; ds[i]-
>nhap();
}
cout << "\nDanh sach nhan vien:\n";
for (int i = 0; i < n; i++) { ds[i]-
>xuat(); delete ds[i];
}
return 0;
}
i s 3: Đanh mo
1. Trc nghim:
a. C → virtual void func() = 0;
b. C → Hàm ảo và con tr lp cha
lO MoARcPSD|45467232
2. T lun:
Phân biệt đa nh nh đa nh động. Ưu nhược điểm ca mi loi.
Đa nh (Polymorphism) mt trong nhng tr ct ca OOP, cho phép mt giao din duy nht
có th đưc s dng cho nhiu kiu d liu khác nhau. hai loại đa hình chính:
1. Đa hình nh (Static Polymorphism - Compile-time Polymorphism)
Định nghĩa: dạng đa nh xảy ra trong quá tnh bn dch (compile-time). Trình biên dch s
xác đnh phn bn hàm o được gi da trên kiu d liu hoc s ng/kiu đối s.
Cách thc hin:
Np chng m (Function Overloading): Nhiu m có cùng n nhưng khác nhau về s ng
hoc kiu đối s.
Np chng toán t (Operator Overloading): Định nghĩa lại ý nga ca các toán t cho các kiu
d liu do người dùng định nga.
Mu m (Function Templates): Viết mt hàm tng quát có th hoạt động vi nhiu kiu d liu
kc nhau.
Ưu điểm:
Hiu năng cao: Vì vic gi m được xác định ti thời điểm bn dch, kng có chi phí b sung
trong thi gian chy.
Kim tra li sm: Li xy ra nếu không m thym phù hp s đưc o trong q trình bn
dch.
Nhược điểm:
Ít linh hot: Không th thay đổi nh vi ca m trong thi gian chy. Các quyết định v nh vi
phi được đưa ra trước khi chương trình chạy.
Khó m rng: Khi mun thêm mt hành vi mi, có th phải thay đổi mã ngun hin có hoc to
thêm các phiên bn np chng.
2. Đa hình động (Dynamic Polymorphism - Run-time Polymorphism)
Định nghĩa: dạng đa nh xy ra trong quá trình thực thi chương trình (run-time). Trình bn
dch kng biết phn bn hàm nào s đưc gọi cho đến khi chương trình chạy, mà vic này
đưc quyết định da trên kiu đối tượng thc tế mà con tr hoc tham chiếu tr ti.
Cách thc hin:
Ghi đèm (Function Overriding): Hàm o (virtual function) trong lớp cơ s được ghi đè
(override) trong các lp dn xut.
Hàm o thun túy (Pure Virtual Function) và lp trừu tượng (Abstract Class): Buc các lp con
phi trin khai mtm c th.
Ưu đim:
nh linh hot cao: Cho phép nh vi của đối tượng thay đổi trong thi gian chy, tùy thuc vào
loi đối tượng thc tế.
Kh ng m rng tt: Dng thêm các lp con mi mà kng cần thay đổi mã ca lp cha
hoc các lp con kc, ch cần đảm bo các lp con mới ghi đè m o.
Code d đọc quản hơn: Khi làm vic với các đối tượng thuc cùng mt h thng phân cp,
bn có th tươngc với chúng thông qua con tr hoc tham chiếu đến lớp cơ s.
Nhược điểm:
lO MoARcPSD|45467232
Hiu năng thấp hơn mt ct: Do cn tra cu bng m o (vtable) trong thi gian chy đ xác
đnh phn bn hàm cn gi, có mt chi p nh.
Li có th xy ra trong thi gian chy: Nếu vic trin khai m o kng đúng hoặc có li logic,
li ch phát hin được khi chương trình chạy.
Phân biệt đa hình nh và đa hình động:
Đặc điểm l Đa nh nh (compile-time) l Đanh động (run-time)
Thời điểm xác định l Khi biên dịch l Khi chương trình chạy
Hình thc l Np chng hàm, np chng toán t l Hàm o
Ưu điểm l Hiu sut cao, rõ ràng l Linh hot, h tr kế tha tt
Nhược điểm l Kém linh hot l Hiu sut thp hơn do gọi gián tiếp
3. Lp trình:
#include <iostream> using
namespace std;
class ThanhToan {
public:
virtual float tinhTien(float soTien) = 0;
virtual ~ThanhToan() {}
};
class ThanhToanTienMat : public ThanhToan {
public:
float tinhTien(float soTien) override {
return soTien * 0.95; // chiết khu 5%
}
};
class ThanhToanChuyenKhoan : public ThanhToan {
public:
float tinhTien(float soTien) override {
return soTien * 0.98; // chiết khu 2%
}
};
int main() {
ThanhToan* p;
float soTien;
int luaChon;
lO MoARcPSD|45467232
cout << "Nhap so tien: "; cin >> soTien; cout << "Chon
phuong thuc (1: Tien mat, 2: Chuyen khoan): "; cin >>
luaChon;
if (luaChon == 1) p = new
ThanhToanTienMat; else
p = new ThanhToanChuyenKhoan;
cout << "So tien sau khi thanh toan: " << p->tinhTien(soTien) <<
endl; delete p; return 0;
}
i s 4: Qun lý b nh và con tr trong OOP
1. Trc nghim:
a. C → new
b. C → Gii phóng tài nguyên
2. T lun:
Constructor vs Destructor:
Constructor: Hàm khi to, gi khi to đối tượng.
Destructor: Hàm hy, gọi khi đối tượng b hy (dùng gii pngi nguyên như bộ nh, file...).
Dynamic Allocation (Cp pt đng):
Dùng khi s ợng đối tượng không biết trước lúc bn dch (runtime). S
dng t ka new, gii png bng delete hoc delete[].
Gii thích s kc bit gia constructor, destructor khi o ng cấp pt động (dynamic
allocation).
1. Constructor (Hàm to)
Định nghĩa: Constructor một m thành viên đặc bit ca mt lớp, được gi t động khi mt
đối tượng ca lớp đó được to ra. Tên ca constructor phi ging ht n ca lp và không
có kiu tr v (k c void).
Mục đích:
Khi tạo đối tượng: Đảm bo rng đối tượng được khi to trng thái hp l ngay sau khi
đưc to.
Cp phát i ngun: Thc hin cp phát b nh đng, m tp, kết nối cơ s d liu, hoc bt
k i nguyên o khác mà đối tượng cn.
Ví d: Khi bn khai o SinhVien sv; hoc SinhVien* sv = new SinhVien();, constructor ca lp
SinhVien s đưc gi.
2. Destructor (Hàm hy)
Định nghĩa: Destructor cũng là mộtm thành vn đặc bit ca mt lớp, được gi t đng khi
mt đối tượng ca lp đó bị hy (ví d: khi đối tượng ra khi phm vi, khi chương tnh kết thúc,
lO MoARcPSD|45467232
hoc khi delete một đối tượng được cấp pt đng). Tên ca destructor du ngã (~) theo sau
n lp (ví d: ~ClassName()) kng có kiu tr về, cũng không nhận đối s.
Mục đích:
Gii phóng tài nguyên: Thc hin các công vic dn dp, như giải png b nh động đã được
cp phát bi constructor hoc các phương thức kc, đóng tệp, đóng kết ni cơ s d liu,
v.v., đ tránh rò ri nguyên.
Đảm bo i nguyên được tr li h thng: Tránh nh trng "r b nh" (memory leak) hoc
các i ngun kc b chiếm dng mà kng được gii phóng.
Ví d: Khi sv trong SinhVien sv; ra khi phm vi, hoc khi bn gi delete sv; cho một đối tượng
đưc cấp phát đng, destructor ca lp SinhVien s đưc gi.
Khi o ng cấp phát động (Dynamic Allocation)?
Cấp phát động (s dng new và delete trong C++) là quá trình cp phát b nh trong thi gian
chy (run-time) t heap (vùng nh t do), thay vì cp pt trong thi gian biên dch
(compile-time) t stack. Chúng ta nên ng cấp pt động trong các trường hp sau:
ch thước d liu không biết trước khi biên dch: Khi bn cn to mt mng hoc mt cu trúc
d liu mà ch thước ca ch được xác đnh trong thi gian chy (ví d: người dùng nhp
s ng phn t).
D liu cn tn ti ngoài phm vi m: Khi một đối tượng cn tn ti ngay c sau khi m to ra
nó đã kết thúc. Các đối tượng được cp pt trên stack s t đng b hy khi m kết thúc,
nhưng đối tượng trên heap vn tn ti cho đến khi được delete th công.
To các cu trúc d liu linh hot: Ví d như danh sách ln kết, cây, đ th, nơi các nút được
thêm hoc xóa mt cách linh hot trong thi gian chy.
Đa nh động (Dynamic Polymorphism): Khi bn mun s dng con tr hoc tham chiếu ca
lớp cơ s để tr đến các đối tượng ca lp dn xut và gi các hàm ảo (như trong Bài 3). Điều
này u cầu các đối tượng được cấp phát động.
Khi m vic vi các tài nguyên lớn: Đối với các đối tượng q ln kng th cp phát trên
stack (stack có gii hạn kích thước).
Lưu ý quan trọng: Khi s dng new đ cp phát b nh đng, bn phi luôn s dụng delete để
gii phóng b nh đó khi kng còn cần đến nữa để tránh rò r b nhớ. Đối vi mng cp phát
đng (new Type[size]), bn phi ng delete[] để gii phóng.
3. Lp trình:
#include <iostream> using
namespace std;
class SinhVien { private:
string ten;
float diemTB; public:
void nhap() { cout << "Ten SV: "; cin.ignore();
getline(cin, ten); cout << "Diem TB: "; cin >>
diemTB;
}
lO MoARcPSD|45467232
void xuat() { cout << "Ten: " << ten << ", Diem TB: " <<
diemTB << endl;
}
};
int main() {
int n;
cout << "Nhap so sinh vien: "; cin >> n;
SinhVien* ds = new SinhVien[n];
for (int i = 0; i < n; i++) { cout <<
"\nNhap SV thu " << i + 1 << ":\n";
ds[i].nhap();
}
cout << "\nDanh sach sinh vien:\n";
for (int i = 0; i < n; i++) {
ds[i].xuat();
}
delete[] ds;
return 0;
}
i s 5: Mô nh a h thng bng lớp và đối tượng
1. Trc nghim:
a. C → Ngôn ng mô nh a hướng đối tượng
b. C → Thành phần lớp đối tượng lp kc
2. T lun:
Quan h trong UML:
Loi quan h l Ý nga l Ký hiệu UML
Kế tha (generalization) l Lp con kế tha lp cha l Tam gc trng
Kết hp (association) l Mt lp ln kết vi lp kc (có th 1-nhiều) l Mũi tên đơn
Tp hp (aggregation) l Mt lp cha lp kc (có th đc lp) l Hình thoi rng
Thành phn (composition) l Lp cha lp kc (ph thuc sng chết) l Hình thoi đen Trình y
các quan h gia các lp trong UML: kế tha, kết hp, tp hp.
Trong UML (Unified Modeling Language), các quan h gia các lp là cách th hin s tương
c và ph thuc gia cng trong mt h thng. Dưới đây ba quan h cơ bản:
1. Kế tha (Inheritance / Generalization)
lO MoARcPSD|45467232
Ý nga: Th hin mi quan h "là mt loi" (is-a kind of). Mt lp con kế tha các thuc tính và
phương thức t lp cha. Lp con m rng hoc ghi đè các hành vi ca lp cha.
hiu UML: Một đường lin t vi mũin rỗng (hình tam giác) tr t lp con đến lp cha. Ví
d: Dog kế tha t Animal (A Dog is a kind of Animal).
Đặc điểm:
Gp i s dng mã.
To ra mt h thng phân cp các lp.
Thúc đynh đa nh động (khi s dng m o).
2. Kết hp (Association)
Ý nga: Th hin mi quan h chung gia hai lớp, trong đó mt lp "có" hoc "s dng" mt
hoc nhiu đối tượng ca lớp kc. Đây mi quan h yếu hơn so vi tp hp hoc hp
thành.
hiu UML: Mt đường thng lin t gia hai lp, có th có mũi tên chỉ ng ca s tương
c, và có th có bi s (multiplicity) hai đầu (ví d: 1, 0..*, 1..*).
Ví d: Student kết hp vi Course (A Student takes many Courses).
Đặc điểm:
Các đối tượng có th tn ti độc lp vi nhau.
Không có s s hu mnh m v ng đời.
3. Tp hp (Aggregation)
Ý nga: Là mt dạng đặc bit ca kết hp, th hin mi quan h "mt phn ca" (part-of)
nhưng yếu hơn hợp thành. Mt đối tượng lớn hơn (whole) chứa các đối tượng nh hơn (parts),
nhưng các đối tượng con có th tn ti đc lp nếu đối tượng cha b hy.
hiu UML: Một đường lin t vi mt hình thoi rng phía lp "toàn th" (whole) mt
đưng thng đến lp "tnh phn" (part).
Ví d: Library tp hp Book (A Library has Books). Nếu thư viện đóng ca, các cun sách vn
tn ti.
Đặc điểm:
Mi quan h "có" (has-a) nhưng các thành phần không b ph thuộc vào vòng đời ca đối tượng
cha nó.
Các thành phn có th đưc chia s gia nhiu đối tượng "toàn th".
4. Hp thành (Composition) - (Thường được xem xét cùng vi Tp hp)
Ý nga: Là mt dng mnh nht ca kết hp, th hin mi quan h " mt phn kng th
ch ri ca" (is-a part-of, mandatory). Các đối tượng con kng th tn tại đc lp với đối
ng cha. Nếu đối tượng cha b hy, các đối tượng con cũng bị hy theo.
hiu UML: Một đường lin t vi một hình thoi đặcen) ở phía lp "toàn th" (whole) và
mt đường thẳng đến lp "thành phn" (part).
Ví d: House hp thành Room (A House has Rooms). Nếu căn n bị p hy, các phòng cũng
kng còn tn ti. Đặc điểm:
Mi quan h "có" (has-a) mnh mẽ, vòng đời ca các thành phn ph thuc hn toàn o đối
ng cha nó.
Các thành phn không th đưc chia s.
3. Lp trình:
lO MoARcPSD|45467232
#include <iostream> using
namespace std;
class NhaXuatBan { private:
string tenNXB;
int namTL; public:
void nhap() { cout << "Ten NXB: "; cin.ignore();
getline(cin, tenNXB); cout << "Nam thanh lap: "; cin >>
namTL;
}
void xuat() {
cout << "NXB: " << tenNXB << ", Nam TL: " << namTL;
}
};
class Sach { private:
string maSach, tenSach;
NhaXuatBan nxb; // Quan h "has-a" public:
void nhap() { cout << "Ma sach: "; cin
>> maSach; cin.ignore(); cout <<
"Ten sach: "; getline(cin, tenSach); cout
<< "---Nhap thong tin NXB---\n";
nxb.nhap();
}
void xuat() { cout << "\nMa: " << maSach << ", Ten: " <<
tenSach << ", "; nxb.xuat(); cout << endl;
}
};
int main() {
int n; cout
<< "Nhap so
sach: "; cin
>> n;
Sach* ds = new Sach[n];
for (int i = 0; i < n; i++) { cout << "\nNhap
sach thu " << i + 1 << ":\n"; ds[i].nhap();
}
cout << "\nDanh sach sach:\n";
for (int i = 0; i < n; i++) {
ds[i].xuat();
}
lO MoARcPSD|45467232
delete[] ds;
return 0;
}

Preview text:

lO M oARcPSD| 45467232
Bài số 1: Tổng quan lập trình hướng đối tượng
1. Trắc nghiệm (2 điểm)
a. Lợi ích chính của OOP là gì?
A. Tăng hiệu năng chương trình B. Giảm số dòng lệnh
C. Tăng tính mô-đun, bảo trì và tái sử dụng D. Không cần viết hàm
b. Câu lệnh nào dùng để tạo đối tượng từ lớp trong C++? A. class a = new A(); B. A a; C. A = new object(); D. object A = new A(); 2. Tự luận (3 điểm)
Trình bày đặc điểm của lập trình hướng đối tượng và so sánh với lập trình cấu trúc. 3. Lập trình (5 điểm)
Viết chương trình định nghĩa lớp SinhVien gồm: mã SV, tên SV, điểm KTLT. Nhập danh sách
sinh viên và in danh sách ra màn hình.
Bài số 2: Kế thừa và tính trừu tượng trong C++
1. Trắc nghiệm (2 điểm)
a. Trong kế thừa, từ khóa nào giúp lớp con kế thừa công khai lớp cha? A. inherit B. extends C. public D. private
b. Tính trừu tượng thể hiện rõ nhất qua đâu? A. Hàm thành viên tĩnh B. Hàm ảo
C. Lớp trừu tượng (abstract class) D. Giao diện 2. Tự luận (3 điểm)
Trình bày vai trò của tính trừu tượng trong thiết kế phần mềm. So sánh lớp trừu tượng và lớp giao diện. 3. Lập trình (5 điểm)
Xây dựng lớp trừu tượng NhanVien với hàm ảo tinhLuong(). Hai lớp con:
- NVCongNhat: lương = số ngày * 300k
- NVSanPham: lương = số sản phẩm * 200k
Viết chương trình chính quản lý danh sách nhân viên. lO M oARcPSD| 45467232
Bài số 3: Đa hình và hàm ảo
1. Trắc nghiệm (2 điểm)
a. Hàm ảo thuần túy được khai báo như thế nào? A. virtual void func(); B. void func() = 0; C. virtual void func() = 0; D. abstract func();
b. Đa hình động được thực hiện qua? A. Hàm main B. Hàm tạo
C. Hàm ảo và con trỏ lớp cha D. Kế thừa nhiều lớp 2. Tự luận (3 điểm)
Phân biệt đa hình tĩnh và đa hình động. Ưu nhược điểm của mỗi loại. 3. Lập trình (5 điểm)
Tạo lớp Cha có hàm ảo tinhTien(). Hai lớp con: - ThanhToanTienMat - ThanhToanChuyenKhoan
Ghi đè hàm tinhTien với chiết khấu khác nhau. Viết chương trình quản lý và gọi hàm bằng con trỏ lớp cha.
Bài số 4: Quản lý bộ nhớ và con trỏ trong OOP
1. Trắc nghiệm (2 điểm)
a. Trong C++, từ khóa nào được dùng để cấp phát động bộ nhớ? A. malloc B. alloc C. new D. pointer
b. Khi nào cần dùng destructor?
A. Khởi tạo đối tượng B. Gán đối tượng C. Giải phóng tài nguyên D. Sửa dữ liệu 2. Tự luận (3 điểm) lO M oARcPSD| 45467232
Giải thích sự khác biệt giữa constructor, destructor và khi nào dùng cấp phát động (dynamic allocation). 3. Lập trình (5 điểm)
Viết chương trình quản lý sinh viên với mảng cấp phát động. Lớp SinhVien gồm: tên, điểm TB.
Nhập N sinh viên và xuất danh sách.
Bài số 5: Mô hình hóa hệ thống bằng lớp và đối tượng 1. Trắc nghiệm (2 điểm) a. UML là gì?
A. Ngôn ngữ lập trình hướng đối tượng B. Công cụ phân tích dữ liệu
C. Ngôn ngữ mô hình hóa hướng đối tượng D. Một IDE
b. Quan hệ "has-a" trong OOP thể hiện qua? A. Kế thừa B. Giao diện
C. Thành phần lớp là đối tượng lớp khác D. Tính đa hình 2. Tự luận (3 điểm)
Trình bày các quan hệ giữa các lớp trong UML: kế thừa, kết hợp, tập hợp. 3. Lập trình (5 điểm)
Thiết kế hệ thống quản lý thư viện gồm các lớp: - Sach: mã sách, tên sách
- NhaXuatBan: tên NXB, năm thành lập
- Mỗi sách có 1 NXB → dùng quan hệ "has-a"
Nhập danh sách sách và in thông tin ra màn hình. Giải
Bài số 1: Tổng quan lập trình hướng đối tượng 1. Trắc nghiệm:
a. C → Tăng tính mô-đun, bảo trì và tái sử dụng b. B → A a; 2. Tự luận:
Đặc điểm của lập trình hướng đối tượng (OOP): Đóng gói (Encapsulation) Kế thừa (Inheritance) Đa hình (Polymorphism)
Trừu tượng hóa (Abstraction) lO M oARcPSD| 45467232 3. Lập trình: #include using namespace std; class SinhVien { private: string maSV, tenSV; float diemKTLT; public:
void nhap() { cout << "Ma SV: "; cin
>> maSV; cin.ignore(); cout <<
"Ten SV: "; getline(cin, tenSV); cout <<
"Diem KTLT: "; cin >> diemKTLT; }
void xuat() { cout << "Ma: " << maSV << ", Ten: " << tenSV << ", Diem: " << diemKTLT << endl; } }; int main() { int n;
cout << "Nhap so SV: "; cin >> n;
SinhVien* ds = new SinhVien[n]; for (int i =
0; i < n; i++) { cout << "\nNhap SV thu "
<< i + 1 << ":\n"; ds[i].nhap(); } lO M oARcPSD| 45467232
cout << "\nDanh sach sinh vien:\n";
for (int i = 0; i < n; i++) { ds[i].xuat(); } delete[] ds; return 0; }
Bài số 2: Kế thừa và tính trừu tượng 1. Trắc nghiệm: a. C → public
b. C → Lớp trừu tượng (abstract class) 2. Tự luận:
Vai trò của trừu tượng: Ẩn chi tiết cài đặt
Giúp thiết kế hệ thống linh hoạt, dễ mở rộng
-Đơn giản hóa độ phức tạp: Tính trừu tượng giúp ẩn đi các chi tiết triển khai phức tạp bên
trong, chỉ hiển thị những thông tin và chức năng cần thiết cho người sử dụng. Điều này giúp
người lập trình tập trung vào "cái gì" mà không cần quan tâm đến "như thế nào".
-Tăng tính mô-đun hóa: Bằng cách định nghĩa các giao diện trừu tượng, chúng ta có thể chia hệ
thống thành các module độc lập. Mỗi module có thể được phát triển và kiểm thử riêng biệt, sau
đó tích hợp lại với nhau.
-Dễ bảo trì và mở rộng: Khi các chi tiết triển khai được ẩn đi, việc thay đổi hoặc nâng cấp một
phần của hệ thống sẽ ít ảnh hưởng đến các phần khác, giúp giảm thiểu rủi ro và chi phí bảo trì.
Đồng thời, việc thêm các chức năng mới cũng dễ dàng hơn.
-Thúc đẩy tái sử dụng mã: Các lớp trừu tượng hoặc giao diện định nghĩa một khuôn mẫu
chung, cho phép các lớp con triển khai theo cách riêng của mình nhưng vẫn tuân thủ một cấu
trúc nhất định. Điều này thúc đẩy việc tái sử dụng mã và giảm sự trùng lặp.
-Tạo ra một kiến trúc rõ ràng: Tính trừu tượng giúp định nghĩa các tầng (layers) và thành phần
(components) trong kiến trúc phần mềm một cách rõ ràng, dễ hiểu và dễ quản lý. lO M oARcPSD| 45467232 3. Lập trình: #include using namespace std; class NhanVien { public:
virtual float tinhLuong() = 0; virtual void nhap() = 0;
virtual void xuat() = 0; virtual ~NhanVien() {} };
class NVCongNhat : public NhanVien { private: int soNgay; public: void nhap() {
cout << "Nhap so ngay lam: "; cin >> soNgay; } lO M oARcPSD| 45467232 float tinhLuong() override { return soNgay * 300000; }
void xuat() { cout << "NVCongNhat - Luong: " << tinhLuong() << endl; } };
class NVSanPham : public NhanVien { private: int soSP; public:
void nhap() { cout << "Nhap so san pham: "; cin >> soSP; } float tinhLuong() override { return soSP * 200000; }
void xuat() { cout << "NVSanPham - Luong: " << tinhLuong() << endl; } }; int main() { int n;
cout << "Nhap so NV: "; cin >> n; NhanVien* ds[100];
for (int i = 0; i < n; i++) { int loai;
cout << "\nNhan vien thu " << i + 1 << " (1-Cong Nhat, 2-San Pham): "; cin >> loai;
if (loai == 1) ds[i] = new NVCongNhat; else ds[i] = new NVSanPham; ds[i]- >nhap(); }
cout << "\nDanh sach nhan vien:\n";
for (int i = 0; i < n; i++) { ds[i]- >xuat(); delete ds[i]; } return 0; }
Bài số 3: Đa hình và hàm ảo 1. Trắc nghiệm:
a. C → virtual void func() = 0;
b. C → Hàm ảo và con trỏ lớp cha lO M oARcPSD| 45467232 2. Tự luận:
Phân biệt đa hình tĩnh và đa hình động. Ưu nhược điểm của mỗi loại.
Đa hình (Polymorphism) là một trong những trụ cột của OOP, cho phép một giao diện duy nhất
có thể được sử dụng cho nhiều kiểu dữ liệu khác nhau. Có hai loại đa hình chính:
1. Đa hình tĩnh (Static Polymorphism - Compile-time Polymorphism)
Định nghĩa: Là dạng đa hình xảy ra trong quá trình biên dịch (compile-time). Trình biên dịch sẽ
xác định phiên bản hàm nào được gọi dựa trên kiểu dữ liệu hoặc số lượng/kiểu đối số. Cách thực hiện:
Nạp chồng hàm (Function Overloading): Nhiều hàm có cùng tên nhưng khác nhau về số lượng hoặc kiểu đối số.
Nạp chồng toán tử (Operator Overloading): Định nghĩa lại ý nghĩa của các toán tử cho các kiểu
dữ liệu do người dùng định nghĩa.
Mẫu hàm (Function Templates): Viết một hàm tổng quát có thể hoạt động với nhiều kiểu dữ liệu khác nhau. Ưu điểm:
Hiệu năng cao: Vì việc gọi hàm được xác định tại thời điểm biên dịch, không có chi phí bổ sung trong thời gian chạy.
Kiểm tra lỗi sớm: Lỗi xảy ra nếu không tìm thấy hàm phù hợp sẽ được báo trong quá trình biên dịch. Nhược điểm:
Ít linh hoạt: Không thể thay đổi hành vi của hàm trong thời gian chạy. Các quyết định về hành vi
phải được đưa ra trước khi chương trình chạy.
Khó mở rộng: Khi muốn thêm một hành vi mới, có thể phải thay đổi mã nguồn hiện có hoặc tạo
thêm các phiên bản nạp chồng.
2. Đa hình động (Dynamic Polymorphism - Run-time Polymorphism)
Định nghĩa: Là dạng đa hình xảy ra trong quá trình thực thi chương trình (run-time). Trình biên
dịch không biết phiên bản hàm nào sẽ được gọi cho đến khi chương trình chạy, mà việc này
được quyết định dựa trên kiểu đối tượng thực tế mà con trỏ hoặc tham chiếu trỏ tới. Cách thực hiện:
Ghi đè hàm (Function Overriding): Hàm ảo (virtual function) trong lớp cơ sở được ghi đè
(override) trong các lớp dẫn xuất.
Hàm ảo thuần túy (Pure Virtual Function) và lớp trừu tượng (Abstract Class): Buộc các lớp con
phải triển khai một hàm cụ thể. Ưu điểm:
Tính linh hoạt cao: Cho phép hành vi của đối tượng thay đổi trong thời gian chạy, tùy thuộc vào
loại đối tượng thực tế.
Khả năng mở rộng tốt: Dễ dàng thêm các lớp con mới mà không cần thay đổi mã của lớp cha
hoặc các lớp con khác, chỉ cần đảm bảo các lớp con mới ghi đè hàm ảo.
Code dễ đọc và quản lý hơn: Khi làm việc với các đối tượng thuộc cùng một hệ thống phân cấp,
bạn có thể tương tác với chúng thông qua con trỏ hoặc tham chiếu đến lớp cơ sở. Nhược điểm: lO M oARcPSD| 45467232
Hiệu năng thấp hơn một chút: Do cần tra cứu bảng hàm ảo (vtable) trong thời gian chạy để xác
định phiên bản hàm cần gọi, có một chi phí nhỏ.
Lỗi có thể xảy ra trong thời gian chạy: Nếu việc triển khai hàm ảo không đúng hoặc có lỗi logic,
lỗi chỉ phát hiện được khi chương trình chạy.
Phân biệt đa hình tĩnh và đa hình động:
Đặc điểm l Đa hình tĩnh (compile-time) l Đa hình động (run-time)
Thời điểm xác định l Khi biên dịch l Khi chương trình chạy
Hình thức l Nạp chồng hàm, nạp chồng toán tử l Hàm ảo
Ưu điểm l Hiệu suất cao, rõ ràng l Linh hoạt, hỗ trợ kế thừa tốt
Nhược điểm l Kém linh hoạt l Hiệu suất thấp hơn do gọi gián tiếp 3. Lập trình: #include using namespace std; class ThanhToan { public:
virtual float tinhTien(float soTien) = 0; virtual ~ThanhToan() {} };
class ThanhToanTienMat : public ThanhToan { public:
float tinhTien(float soTien) override {
return soTien * 0.95; // chiết khấu 5% } };
class ThanhToanChuyenKhoan : public ThanhToan { public:
float tinhTien(float soTien) override {
return soTien * 0.98; // chiết khấu 2% } }; int main() { ThanhToan* p; float soTien; int luaChon; lO M oARcPSD| 45467232
cout << "Nhap so tien: "; cin >> soTien; cout << "Chon
phuong thuc (1: Tien mat, 2: Chuyen khoan): "; cin >> luaChon; if (luaChon == 1) p = new ThanhToanTienMat; else
p = new ThanhToanChuyenKhoan;
cout << "So tien sau khi thanh toan: " << p->tinhTien(soTien) << endl; delete p; return 0; }
Bài số 4: Quản lý bộ nhớ và con trỏ trong OOP 1. Trắc nghiệm: a. C → new
b. C → Giải phóng tài nguyên 2. Tự luận: Constructor vs Destructor:
Constructor: Hàm khởi tạo, gọi khi tạo đối tượng.
Destructor: Hàm hủy, gọi khi đối tượng bị hủy (dùng giải phóng tài nguyên như bộ nhớ, file...).
Dynamic Allocation (Cấp phát động):
Dùng khi số lượng đối tượng không biết trước lúc biên dịch (runtime). Sử
dụng từ khóa new, giải phóng bằng delete hoặc delete[].
Giải thích sự khác biệt giữa constructor, destructor và khi nào dùng cấp phát động (dynamic allocation). 1. Constructor (Hàm tạo)
Định nghĩa: Constructor là một hàm thành viên đặc biệt của một lớp, được gọi tự động khi một
đối tượng của lớp đó được tạo ra. Tên của constructor phải giống hệt tên của lớp và nó không
có kiểu trả về (kể cả void). Mục đích:
Khởi tạo đối tượng: Đảm bảo rằng đối tượng được khởi tạo ở trạng thái hợp lệ ngay sau khi nó được tạo.
Cấp phát tài nguyên: Thực hiện cấp phát bộ nhớ động, mở tệp, kết nối cơ sở dữ liệu, hoặc bất
kỳ tài nguyên nào khác mà đối tượng cần.
Ví dụ: Khi bạn khai báo SinhVien sv; hoặc SinhVien* sv = new SinhVien();, constructor của lớp SinhVien sẽ được gọi. 2. Destructor (Hàm hủy)
Định nghĩa: Destructor cũng là một hàm thành viên đặc biệt của một lớp, được gọi tự động khi
một đối tượng của lớp đó bị hủy (ví dụ: khi đối tượng ra khỏi phạm vi, khi chương trình kết thúc, lO M oARcPSD| 45467232
hoặc khi delete một đối tượng được cấp phát động). Tên của destructor là dấu ngã (~) theo sau
là tên lớp (ví dụ: ~ClassName()) và nó không có kiểu trả về, cũng không nhận đối số. Mục đích:
Giải phóng tài nguyên: Thực hiện các công việc dọn dẹp, như giải phóng bộ nhớ động đã được
cấp phát bởi constructor hoặc các phương thức khác, đóng tệp, đóng kết nối cơ sở dữ liệu,
v.v., để tránh rò rỉ tài nguyên.
Đảm bảo tài nguyên được trả lại hệ thống: Tránh tình trạng "rò rỉ bộ nhớ" (memory leak) hoặc
các tài nguyên khác bị chiếm dụng mà không được giải phóng.
Ví dụ: Khi sv trong SinhVien sv; ra khỏi phạm vi, hoặc khi bạn gọi delete sv; cho một đối tượng
được cấp phát động, destructor của lớp SinhVien sẽ được gọi.
Khi nào dùng cấp phát động (Dynamic Allocation)?
Cấp phát động (sử dụng new và delete trong C++) là quá trình cấp phát bộ nhớ trong thời gian
chạy (run-time) từ heap (vùng nhớ tự do), thay vì cấp phát trong thời gian biên dịch
(compile-time) từ stack. Chúng ta nên dùng cấp phát động trong các trường hợp sau:
Kích thước dữ liệu không biết trước khi biên dịch: Khi bạn cần tạo một mảng hoặc một cấu trúc
dữ liệu mà kích thước của nó chỉ được xác định trong thời gian chạy (ví dụ: người dùng nhập số lượng phần tử).
Dữ liệu cần tồn tại ngoài phạm vi hàm: Khi một đối tượng cần tồn tại ngay cả sau khi hàm tạo ra
nó đã kết thúc. Các đối tượng được cấp phát trên stack sẽ tự động bị hủy khi hàm kết thúc,
nhưng đối tượng trên heap vẫn tồn tại cho đến khi được delete thủ công.
Tạo các cấu trúc dữ liệu linh hoạt: Ví dụ như danh sách liên kết, cây, đồ thị, nơi các nút được
thêm hoặc xóa một cách linh hoạt trong thời gian chạy.
Đa hình động (Dynamic Polymorphism): Khi bạn muốn sử dụng con trỏ hoặc tham chiếu của
lớp cơ sở để trỏ đến các đối tượng của lớp dẫn xuất và gọi các hàm ảo (như trong Bài 3). Điều
này yêu cầu các đối tượng được cấp phát động.
Khi làm việc với các tài nguyên lớn: Đối với các đối tượng quá lớn không thể cấp phát trên
stack (stack có giới hạn kích thước).
Lưu ý quan trọng: Khi sử dụng new để cấp phát bộ nhớ động, bạn phải luôn sử dụng delete để
giải phóng bộ nhớ đó khi không còn cần đến nữa để tránh rò rỉ bộ nhớ. Đối với mảng cấp phát
động (new Type[size]), bạn phải dùng delete[] để giải phóng. 3. Lập trình: #include using namespace std; class SinhVien { private: string ten; float diemTB; public:
void nhap() { cout << "Ten SV: "; cin.ignore();
getline(cin, ten); cout << "Diem TB: "; cin >> diemTB; } lO M oARcPSD| 45467232
void xuat() { cout << "Ten: " << ten << ", Diem TB: " << diemTB << endl; } }; int main() { int n;
cout << "Nhap so sinh vien: "; cin >> n;
SinhVien* ds = new SinhVien[n];
for (int i = 0; i < n; i++) { cout <<
"\nNhap SV thu " << i + 1 << ":\n"; ds[i].nhap(); }
cout << "\nDanh sach sinh vien:\n";
for (int i = 0; i < n; i++) { ds[i].xuat(); } delete[] ds; return 0; }
Bài số 5: Mô hình hóa hệ thống bằng lớp và đối tượng 1. Trắc nghiệm:
a. C → Ngôn ngữ mô hình hóa hướng đối tượng
b. C → Thành phần lớp là đối tượng lớp khác 2. Tự luận: Quan hệ trong UML:
Loại quan hệ l Ý nghĩa l Ký hiệu UML
Kế thừa (generalization) l Lớp con kế thừa lớp cha l Tam giác trắng
Kết hợp (association) l Một lớp liên kết với lớp khác (có thể 1-nhiều) l Mũi tên đơn
Tập hợp (aggregation) l Một lớp chứa lớp khác (có thể độc lập) l Hình thoi rỗng
Thành phần (composition) l Lớp chứa lớp khác (phụ thuộc sống chết) l Hình thoi đen Trình bày
các quan hệ giữa các lớp trong UML: kế thừa, kết hợp, tập hợp.
Trong UML (Unified Modeling Language), các quan hệ giữa các lớp là cách thể hiện sự tương
tác và phụ thuộc giữa chúng trong một hệ thống. Dưới đây là ba quan hệ cơ bản:
1. Kế thừa (Inheritance / Generalization) lO M oARcPSD| 45467232
Ý nghĩa: Thể hiện mối quan hệ "là một loại" (is-a kind of). Một lớp con kế thừa các thuộc tính và
phương thức từ lớp cha. Lớp con mở rộng hoặc ghi đè các hành vi của lớp cha.
Ký hiệu UML: Một đường liền nét với mũi tên rỗng (hình tam giác) trỏ từ lớp con đến lớp cha. Ví
dụ: Dog kế thừa từ Animal (A Dog is a kind of Animal). Đặc điểm: Giúp tái sử dụng mã.
Tạo ra một hệ thống phân cấp các lớp.
Thúc đẩy tính đa hình động (khi sử dụng hàm ảo). 2. Kết hợp (Association)
Ý nghĩa: Thể hiện mối quan hệ chung giữa hai lớp, trong đó một lớp "có" hoặc "sử dụng" một
hoặc nhiều đối tượng của lớp khác. Đây là mối quan hệ yếu hơn so với tập hợp hoặc hợp thành.
Ký hiệu UML: Một đường thẳng liền nét giữa hai lớp, có thể có mũi tên chỉ hướng của sự tương
tác, và có thể có bội số (multiplicity) ở hai đầu (ví dụ: 1, 0..*, 1..*).
Ví dụ: Student kết hợp với Course (A Student takes many Courses). Đặc điểm:
Các đối tượng có thể tồn tại độc lập với nhau.
Không có sự sở hữu mạnh mẽ về vòng đời. 3. Tập hợp (Aggregation)
Ý nghĩa: Là một dạng đặc biệt của kết hợp, thể hiện mối quan hệ "một phần của" (part-of)
nhưng yếu hơn hợp thành. Một đối tượng lớn hơn (whole) chứa các đối tượng nhỏ hơn (parts),
nhưng các đối tượng con có thể tồn tại độc lập nếu đối tượng cha bị hủy.
Ký hiệu UML: Một đường liền nét với một hình thoi rỗng ở phía lớp "toàn thể" (whole) và một
đường thẳng đến lớp "thành phần" (part).
Ví dụ: Library tập hợp Book (A Library has Books). Nếu thư viện đóng cửa, các cuốn sách vẫn tồn tại. Đặc điểm:
Mối quan hệ "có" (has-a) nhưng các thành phần không bị phụ thuộc vào vòng đời của đối tượng chứa nó.
Các thành phần có thể được chia sẻ giữa nhiều đối tượng "toàn thể".
4. Hợp thành (Composition) - (Thường được xem xét cùng với Tập hợp)
Ý nghĩa: Là một dạng mạnh nhất của kết hợp, thể hiện mối quan hệ "là một phần không thể
tách rời của" (is-a part-of, mandatory). Các đối tượng con không thể tồn tại độc lập với đối
tượng cha. Nếu đối tượng cha bị hủy, các đối tượng con cũng bị hủy theo.
Ký hiệu UML: Một đường liền nét với một hình thoi đặc (đen) ở phía lớp "toàn thể" (whole) và
một đường thẳng đến lớp "thành phần" (part).
Ví dụ: House hợp thành Room (A House has Rooms). Nếu căn nhà bị phá hủy, các phòng cũng
không còn tồn tại. Đặc điểm:
Mối quan hệ "có" (has-a) mạnh mẽ, vòng đời của các thành phần phụ thuộc hoàn toàn vào đối tượng chứa nó.
Các thành phần không thể được chia sẻ. 3. Lập trình: lO M oARcPSD| 45467232 #include using namespace std; class NhaXuatBan { private: string tenNXB; int namTL; public:
void nhap() { cout << "Ten NXB: "; cin.ignore();
getline(cin, tenNXB); cout << "Nam thanh lap: "; cin >> namTL; } void xuat() {
cout << "NXB: " << tenNXB << ", Nam TL: " << namTL; } }; class Sach { private: string maSach, tenSach;
NhaXuatBan nxb; // Quan hệ "has-a" public:
void nhap() { cout << "Ma sach: "; cin
>> maSach; cin.ignore(); cout <<
"Ten sach: "; getline(cin, tenSach); cout
<< "---Nhap thong tin NXB---\n"; nxb.nhap(); }
void xuat() { cout << "\nMa: " << maSach << ", Ten: " <<
tenSach << ", "; nxb.xuat(); cout << endl; } }; int main() { int n; cout << "Nhap so sach: "; cin >> n; Sach* ds = new Sach[n];
for (int i = 0; i < n; i++) { cout << "\nNhap
sach thu " << i + 1 << ":\n"; ds[i].nhap(); }
cout << "\nDanh sach sach:\n";
for (int i = 0; i < n; i++) { ds[i].xuat(); } lO M oARcPSD| 45467232 delete[] ds; return 0; }