lO MoARcPSD| 45467232
Đáp án Ôn tập Lp trình Hướng đối tưng
Phn 1: thuyết
Câu 1: Nêu khái nim v s kế tha và những ưu nhược điểm ca kế tha trong vic lp
trình. Trường hp nào thì có th vi phm tính kế tha? Cho ví d minh ha.
Khái nim: Kế tha (Inheritance) mt trong bn tính cht tr ct ca lp
trình ng đi tưng (OOP). cho phép mt lp (gi lp con hoc lp
dn xut) tha hưởng li c thuc tính (d liệu) phương thức (hành vi)
t mt lp khác (gi lp cha hoc lớp s).
Ưu điểm:
o Tái s dng mã: Không cn phi viết lại code đã có ở lp cha.
o D bo trì và m rng: Khi cần thay đổi, ch cn sa lp cha, các lp con s
t động đưc cp nht. D dàng thêm c lp con mi vi c chc năng
riêng bit.
o To ra mt h thng pn cp logic: Phn ánh mi quan h "is-a" ( mt loi
ca) trong thế gii thc, giúp code d hiểu n.
Nhược điểm: o Liên kết cht ch: Lp con và lp cha b ph thuc ln
nhau. S thay đi lp cha có th gây ra li lp con.
o Phc tp hóa thiết kế: H thng kế tha đa tầng có th tr nên phc tp và
khó qun lý.
Trưng hp vi phm tính kế tha: Xy ra khi mi quan h gia lp con và
lp cha không phi quan h "is-a". Điu này vi phm nguyên tc thay thế
Liskov (Liskov Substitution Principle).
Ví d minh ha: Lp HinhVuong kế tha t HinhChuNhat. Mt hình ch
nht có th thay đi chiu dài và chiu rng một cách đc lập, nhưng hình
vuông thì kng (thay đi mt cnh phải thay đi cnh còn lại). Điu này
phá v hành vi ca lp cha. class HinhChuNhat { protected:
double chieuDai;
double chieuRong;
public:
virtual void setChieuDai(double dai) { this->chieuDai = dai; }
virtual void setChieuRong(double rong) { this->chieuRong = rong;}
double tinhDienTich() const { return chieuDai * chieuRong; }
};
lO MoARcPSD|45467232
// Vi phm: nh vng kng th chiu dài, rộng độc lp
class HinhVuong : public HinhChuNhat { public:
void setCanh(double canh) {
this->chieuDai = canh;
this->chieuRong = canh;
}
// Ghi đè lại đ thay đi hành vi, vi phm nguyên tc Liskov
void setChieuDai(double dai) override { setCanh(dai); }
void setChieuRong(double rong) override { setCanh(rong); }
};
Câu 2: Nêu khái nim v tru tưng hóa và nhng ưu nhược điểm ca trừu tưng hóa
trong vic lp trình. Cho ví d minh ha.
Khái nim: Trừu tượng hóa (Abstraction) quá trình che giu c chi tiết
i đt phc tp và ch hin th các chc năng cần thiết ra bên ngoài. tp
trung vào "cái gì" đi tưng th m, thay vì "làm như thế nào".
Ưu điểm:
o Gim độ phc tp: Ngưi dùng kng cần quan tâm đến cách hoạt động bên
trong.
o Tăng tính bo mt: Che giu c d liu quan trng.
o D dàng thay đổi:th thay đi ch i đặt bên trong mà không nh
ởng đến code s dng lp đó.
Nhược điểm:
o Thiết kế mt giao din tru tượng tt có th khó tn thi gian.
Ví d minh ha: Khi i xe, bn ch cn biết dùng lăng, chân ga, chân
phanh mà không cn biết đng cơ, hộp s bên trong hot đng ra sao.
Trong C++, lp tru tưng và hàm thun o là công c chính đ thc hin.
// Lp trừu tưng "DongVat"
class DongVat { public:
// Giao din chung, kng cn biết chi tiết i đặt
lO MoARcPSD|45467232
virtual void keu() = 0; // Hàm thun o
};
// Lp c th i đặt chi tiết class Meo : public DongVat {
public:
void keu() override {
// Cài đặt c th cho Mèo
// std::cout << "Meow meow";
}
};
Câu 3: Nêu khái nim v đa hình và nhng ưu nhược điểm ca đa hình trong việc lp
trình. Cho ví d minh ha.
Khái nim: Đa hình (Polymorphism) cho phép mt đối tượng có th th
hiện dưới nhiều hình thái khác nhau. Trong C++, nó tờng nghĩa một
li gi hàm th thực thi c hành đng khác nhau tùy thuc vào kiểu đi
ng ti thi đim chy (đa hình đng).
Ưu điểm:
o Linh hot và m rng: D dàng thêm c lp mi mà không cn sa đổi code
hin có.
o Code gn gàng, d đọc: Viết code tng quát x lý đưc nhiu loi đối tưng
khác nhau.
Nhược điểm:
o Khó theo dõi lung chương trình: hành vi c th ch được c đnh ti thi
đim chy.
o Hiu sut: Liên kết đng có th chm hơn mt chút so vi liên kết tĩnh do cn
tra cu trong bng hàm o (vtable).
Ví d minh ha:
#include <iostream>
class DongVat { public:
lO MoARcPSD|45467232
virtual void keu() { std::cout << "Tieng keu dong vat!" << std::endl; }
virtual ~DongVat() {} // Luôn có hàm hy o cho lớp cơ s
};
class Meo : public DongVat { public:
void keu() override { std::cout << "Meow meow" << std::endl; }
};
class Cho : public DongVat { public:
void keu() override { std::cout << "Gau gau" << std::endl; }
};
void ngheTiengKeu(DongVat* dv) {
dv->keu(); // Cùng mt li gi, nhưng hành động khác nhau
}
int main() {
Meo conMeo;
Cho conCho;
ngheTiengKeu(&conMeo); // In ra "Meow meow"
ngheTiengKeu(&conCho); // In ra "Gau gau"
return 0;
}
Câu 4: Nêu khái nim v đóng gói và những ưu nhược điểm ca đóng gói trong việc lp
trình. Trường hp nào thì có th vi phạm tính đóng gói? Cho ví d minh ha.
Khái nim: Đóng gói (Encapsulation) k thut kết hp d liu (thuc tính)
c phương thức x d liệu đó vào trong một th thng nht gi là
lớp (class). cũng che giu thông tin bên trong lp, kng cho phép truy
cp trc tiếp t bên ngoài.
lO MoARcPSD|45467232
Ưu điểm:
o Bo mt d liu: Ngăn chặn truy cp trái phép làm thay đi d liu.
o D qun : Code đưc t chc gn gàng trong các lp.
o Linh hot: Có th thay đổi cu trúc d liu bên trong mà không nh hưởng
đến phn n li của chương trình.
Nhược điểm: o Tăng lưng code cn viết (ví d: c hàm get/set).
Trưng hp vi phạm tính đóng gói:
o Khai báo thuc tính ca lp là public.
o Lm dng hàm bn (friend function) hoc lp bn (friend class).
Ví d minh ha: class TaiKhoanNganHang { private:
// D liệu đưc bo v, không th truy cp t bên ngoài
double soDu;
public:
// Cung cp giao din công khai đ tương tác
void nopTien(double soTien) {
if (soTien > 0) {
soDu += soTien;
}
}
double xemSoDu() {
return soDu;
}
};
Câu 5: a. Phân bit các phm vi truy cp private, protected và public. b. Cho biết ý nghĩa và
mc đích ca c hàm get/set trong mt lp
a. Phân bit các phm vi truy cp:
lO MoARcPSD|45467232
o public: Có th truy cp t bt c đâu (bên trong lp, lp con, bên ngoài
lp).
o protected: Có th truy cp t bên trong lớp đó và các lp con kế tha t .
Không th truy cp t bên ngoài.
o private: Ch có th truy cp t bên trong chính lp đó. Lớp con cũng không
th truy cp.
b. Ý nga và mục đích ca các hàm get/set:
o Mc đích: Cung cp mt giao diện ng khai (public) đ truy cp (get) sa
đổi (set) c thuc tính private mt ch có kim soát.
o Hàm get (Getter/Accessor): Dùng đ ly c) giá tr ca mt thuc tính.
o Hàm set (Setter/Mutator): Dùng đ thiết lp (ghi) giá tr cho mt thuc tính.
m này có th cha logic kim tra tính hp l ca d liệu trưc khi gán.
Câu 6: a. Phân bit khái nim lớp và đối tưng trong lp trình hướng đối tưng. b. Trình
bày khái niệm đa hình trong lập trình hướng đối tượng. Cho ví d minh ha.
a. Phân bit khái nim lp và đối tượng:
o Lp (Class): Là mt bn thiết kế, mt khn mu. định nghĩa các thuộc
tính và phương thức chung cho mt loi đối tượng. Lp không chiếm b nh.
o Đối tưng (Object): mt th hin c th ca mt lớp. Nó đưc to ra t
lp và có trng thái (g tr ca các thuc tính) hành vi riêng. Đi tượng
chiếm ng nh trên RAM.
o Ví d: SinhVien lp, còn sinhVienA sinhVienB là c đối tưng c th.
b. Trình bày khái niệm đa hình: (Câu tr li ging ht Câu 3).
Câu 7: Phân bit c kiu kế tha private, protected, public
Kiu kế tha quyết đnh phm vi truy cp ca các thành viên đưc kế tha t lp cha trong
lp con:
public inheritance (kế tha công khai): o public ca cha -> public ca con.
o protected ca cha -> protected ca con.
o Thườngng cho quan h "is-a" (là mt loi ca). Đây là kiu ph biến nht.
protected inheritance (kế thừa đưc bo v): o public ca cha ->
protected ca con.
o protected ca cha -> protected ca con.
lO MoARcPSD|45467232
private inheritance (kế thừa riêng tư): o public ca cha -> private ca con.
o protected ca cha -> private ca con.
o Thườngng cho quan h "is-implemented-in-terms-of" (được i đt da
trên).
Câu 8 & 10b: Trình bày các đặc điểm quan trng ca lp trình hướng đối tượng
Bốn đặc đim (tr ct) chính ca lập trình hướng đối tưng :
1. Tính tru tưng (Abstraction): Che giu s phc tp, ch đưa ra giao din cn thiết.
2. Tính đóng gói (Encapsulation): i gn d liệu phương thc o mt lp, che
giu d liu.
3. Tính kế tha (Inheritance): Cho phép lp con tha hưng các đc tính ca lp cha.
4. Tính đa hình (Polymorphism): Cho phép đi tượng có nhiu hình thái, mt hành
động th đưc thc hin khác nhau.
Câu 9 & 10a: Trình bày khái nim ca lớp cơ sở trừu tưng (abstract class). Lớp cơ s
tru tượng được cài đặt trong C++ như thế nào? Hàm thun o gì? Lp trừu tưng
gì? Cho ví d minh ha.
Hàm thun o là gì? mt hàm o (virtual function) không phn định nghĩa
(thân hàm) trong lớp s đưc gán bng = 0.
virtual void hamThuanAo() = 0;
Lp trừu tưng gì? lp cha ít nht mt hàm thun o.
o Đặc điểm: Không th tạo đối tưng trc tiếp t lp trừu tượng.
o Mc đích: Dùng m lớp s chung, định nghĩa mt "giao kèo" (interface)
mà tt c c lp con không tru tượng BT BUC phi tuân theo bng ch
định nghĩa (override) li tt c c hàm thun o.
Cài đặt trong C++: Mt lp trong C++ tr thành lp tru tượng khi ta khai báo ít
nht mt hàm thun o trong nó.
// Lp tru tưng
class HinhHoc { public:
virtual float tinhDienTich() = 0; // Hàm thun o
};
lO MoARcPSD|45467232
class HinhTron : public HinhHoc {
private: float banKinh; public:
// Lp con BT BUC phải định nghĩa li hàm thun o
float tinhDienTich() override { return 3.14 * banKinh * banKinh; }
};
Câu 11: Pn bit ki nim overload (ti chồng) và override (ghi đè) trong lp trình
ớng đối tưng.
Tiêu c
Overloading (Ti chng)
Overriding (Ghi đè)
Phm vi
Trong ng mt lp
Gia lp cha lp con
Tên hàm
Ging nhau
Ging nhau
Ch hàm (Tham
s)
Khác nhau (v s ng hoc
kiu)
Ging ht nhau
T ka
Không cn
Dùng virtual lp cha override (khuyến
khích) lp con
Loại đa hình
Đa hình tĩnh (liên kết lúc biên
dch)
Đa hình động (liên kết lúc chy)
Câu 12: Trình bày ki nim Hàm bn, lp bạn. Ưu nhược điểm. Cho ví d minh ha.
Khái nim: friend mt t khóa trong C++ cho phép mt hàm hoc mt lp
("bn") truy cp vào c thành viên private và protected ca mt lp khác.
Ưu điểm:
o Hu ích trong mt s trưng hp đc biệt như nạp chng toán t
(operator<<, operator>>) mà không th hàm thành viên.
Nhược điểm:
o Vi phạm tính đóng gói: Đây là nhược đim ln nht nó pv nguyên tc
che giu thông tin.
o m cho thiết kế tr nên kém trong sáng khó bo thơn nếu b lm dng.
Câu 13: Nêu vai trò ca hàm to (Constructor), hàm hy (destructor) trong định nghĩa lớp.
Ưu nhược điểm ca hai loi hàm này khi s dng trong kế tha. Cho ví d minh ha.
lO MoARcPSD|45467232
Vai trò:
o Hàm to (Constructor): Đưc t động gi khi mt đi tượng được to ra.
Nhim v chính là khi to các g tr ban đầu cho c thuc tính và cp phát
tài nguyên (nếu có).
o Hàm hy (Destructor): Đưc t động gi khi một đối tưng sp b hy.
Nhim v chính là dn dp, gii phóng tài nguyên mà đi tưng đã cp phát.
Trong kế tha:
o Th t gi: m to đưc gi theo th t t lp cha đến lp con. Hàm hy
đưc gi theo th t ngưc li, t lp con đến lp cha.
o Lưu ý quan trng: Hàm hy ca lp cha phi hàm o (virtual) nếu bn có ý
định a mt đi tượng ca lp con thông qua con tr lp cha. Nếu không,
ch hàm hy ca lp cha được gi, gây ra rò r tài nguyên. class Parent {
public:
virtual ~Parent() { /* Hàm hy o bt buc */ }
};
class Child : public Parent { private: int* data; public:
Child() { data = new int[10]; }
~Child() { delete[] data; /* Gii phóng b nh ca Child */ }
};
int main() {
Parent* p = new Child();
delete p; // S gi hàm hy ca Child ri đến Parent, không b r b nh
return 0;
}
Câu 14: Trình bày phép gán trong lập trình hướng đối tưng. Ti sao phi xây dng phép
gán cho lp? Cho ví d minh ha.
Khái nim: Là vic np chng toán t gán (operator=). cho phép sao chép ni
dung t một đối tưng đã tồn ti sang một đối tượng khác ng đã tn ti.
lO MoARcPSD|45467232
Ti sao phi xây dng? Trình biên dch cung cp mt toán t gán mc định, thc
hin sao chép nông (shallow copy). Điều này s gây ra vấn đ nếu lp cha d
liu kiu con tr:
o Sao chép nông: C hai đối ng s cùng tr đến mt ng nh. Khi một đối
ng b hy, đối tượng còn li s tr đến vùng nh không hp l.
o Gii pháp: Ta phi t định nghĩa toán tử gán để thc hin sao chép sâu
(deep copy), tc là cp phát mt vùng nh mới cho đi tượng được gán và
sao chép ni dung sang đó.
Câu 15: Trình bày k thut np chng (overloading) trong các tình hung kng lp trình
ớng đối tưng, trong lập trình hướng đối tưng và hàm bn. Cho ví d minh ha.
Np chng (overloading) là vic to ra nhiều hàm có cùng tên nhưng khác nhau v danh
sách tham s (s ng hoc kiu) trong cùng mt phm vi.
Hàm thông thường (kng phi OOP):
int tinhTong(int a, int b);
double tinhTong(double a, double b);
Hàm thành viên (OOP):
class PhepToan { public:
int cong(int a, int b);
lO MoARcPSD|45467232
double cong(double a, double b);
};
Hàm bn: Có th đưc np chng như hàm thông thưng.
Câu 16: Trình bày k thuật đa năng hóa toán t (np chng toán t) trong xây dng mt
lp. So sánh vi cách xây dựng hàm tính toán tương ng vi tn t. Cho ví d minh ha.
Khái nim: Là mt dạng đc bit ca np chng hàm, cho phép c toán t có sn
của C++ (n+, -, *, /, ==, <<, >>...) hoạt đng với các đi tượng ca lớp do người
dùng định nghĩa.
So sánh:
o Np chng toán t: Cú pháp t nhiên, d đọc: PhanSo kq = ps1 + ps2;
o Hàm tính toán: pháp dài dòng hơn: PhanSo kq = ps1.cong(ps2);
Câu 17: Trình bày k thut liên kết động. Cho ví d minh ha.
Khái nim: Còn gi là liên kết mun (late binding). quá trình c đnh phiên bn
hàm c th nào s đưc thc thi ti thời điểm chy (runtime), thay ti thi
đim biên dch.
Cơ chế: C++ thc hin liên kết động tng qua hàm o (virtual) và con tr/tham
chiếu đến lp cơ s.
Ví d minh ha: Xem li d Câu 3: Đa hình. Li gi dv->keu() chính d v
liên kết động.
Câu 18: Trình bày toán t (). Cho ví d minh ha.
Khái nim: Np chng toán t gi hàm (operator()). cho phép mt đối tượng
ca lp th đưc "gi" như mt hàm. Nhng lớp nvậy đưc gi functor
hoc function object.
#include <iostream>
class CongThem { private: int giaTriThem; public:
CongThem(int v) : giaTriThem(v) {}
int operator()(int so) const { return so
+ giaTriThem;
lO MoARcPSD|45467232
}
};
int main() {
CongThem cong5(5);
std::cout << cong5(10); // Gi đối tưng như mt hàm, kết qu 15
return 0;
}
Câu 19: Trình bày con tr hàm. Cho ví d minh ha.
Khái nim: Là mt biến lưu trữ địa ch ca mt hàm. Thông qua con tr hàm, ta
có th gi hàm mà đang tr ti.
pháp: kiu_tr_v (*tên_con_tr)(danh_sách_tham_s);
#include <iostream>
int cong(int a, int b) { return a + b; }
int tru(int a, int b) { return a - b; }
int main() {
int (*phepToan)(int, int);
phepToan = &cong;
std::cout << "Tong: " << phepToan(5, 3) << std::endl; // 8
phepToan = &tru;
std::cout << "Hieu: " << phepToan(5, 3) << std::endl; // 2
return 0;
}
Câu 20: So sánh hàm to sao chép và phép gán. Cho ví d minh ha.
lO MoARcPSD|45467232
Tiêu Hàm to sao chép (Copy
Phép gán (Assignment Operator)
chí
Constructor)
Mc đích
Khi to mt đối tượng Sao chép d liu t mt đi tượng
mi t một đi tượng đã đã có vào mt đối tưng khác đã có. tn ti.
Thời điểm
gi
MyClass obj2 = obj1; (Khai MyClass obj1, obj2; obj2 = obj1;
báo) (Gán)
Lưu ý
Cn kim tra t gán (if (this != Kng cn kim
tra t gán.
&other)) đ tránh li.
Phn 2: Bài tp
Câu 1: y dng lớp đa thc bc nht...
#include <iostream>
class DaThucBacNhat { private:
float a, b; // F(x) = ax + b
public:
// Hàm tạo đảm bo a != 0
DaThucBacNhat(float heSoA = 1.0, float heSoB = 0.0) : b(heSoB) { a = (heSoA ==
0) ? 1 : heSoA;
}
// a. nh giá tr F(x0)
double tinhGiaTri(double x0) const { return a *
x0 + b;
}
lO MoARcPSD|45467232
// b. m nghim F(x) = 0 double
timNghiem() const {
return -b / a; }
// c. Cng hai đa thc
DaThucBacNhat operator+(const DaThucBacNhat& other) const { return
DaThucBacNhat(this->a + other.a, this->b + other.b);
}
void inDaThuc() const {
std::cout << a << "x + " << b << std::endl;
} };
Câu 3: y dng lớp đơn thc...
#include <iostream> #include
<cmath>
class DonThuc { private:
float a; // h s int
n; // s
public:
DonThuc(float heSoA = 1.0, int soMuN = 1) { a =
(heSoA == 0) ? 1 : heSoA;
n = (soMuN >= 1 && soMuN <= 100) ? soMuN : 1;
}
lO MoARcPSD|45467232
// a. nh giá tr F(x0) double
tinhGiaTri(double x0) const { return a *
pow(x0, n); }
// b. nh nghim F(x) = b void
timNghiem(double b_val) const {
// ... (logic xnghim) }
// c. Cng hai đơn thức void cong(const
DonThuc& other) const { if (this->n == other.n) {
// ... (cng in ra đơn thức tng)
} else {
// ... (in ra đa thc tng)
}
} };
Câu 4: ...Hãy định nga lớp cNgay thích hp...
#include <iostream> using
namespace std;
class cNgay { private:
int ngay, thang, nam; public:
cNgay() : ngay(1), thang(1), nam(1) {} cNgay(int y, int m) : ngay(1),
thang(m), nam(y) {} cNgay(int y, int m, int d) : ngay(d), thang(m),
nam(y) {}
lO MoARcPSD|45467232
bool operator<(const cNgay& other) const { if (nam !=
other.nam) return nam < other.nam; if (thang != other.thang)
return thang < other.thang; return ngay < other.ngay;
}
friend istream& operator>>(istream& is, cNgay& obj); friend ostream&
operator<<(ostream& os, const cNgay& obj);
};
istream& operator>>(istream& is, cNgay& obj) { /* ... */ return is; } ostream&
operator<<(ostream& os, const cNgay& obj) { /* ... */ return os; }
Câu 5: Cho lp Pn s (CPhanSo)...
#include <iostream>
#include <numeric> // Cho std::gcd using
namespace std;
class CPhanSo { private:
int tuSo, mauSo; void
rutGon() { /* ... */ } public:
CPhanSo(int tu = 0, int mau = 1) : tuSo(tu), mauSo(mau) {}
CPhanSo operator+(const CPhanSo& other) const { /* ... */ } bool
operator==(const CPhanSo& other) const { /* ... */ }
friend CPhanSo operator+(const CPhanSo& ps, int x); friend CPhanSo
operator+(int x, const CPhanSo& ps); friend istream& operator>>(istream& is,
CPhanSo& ps); friend ostream& operator<<(ostream& os, const CPhanSo& ps);
};
// ... (định nghĩa c hàm friend)
lO MoARcPSD|45467232
Câu 6: Định nga lớp CDate... #include <iostream>
class CDate { private:
int ngay, thang, nam; // ...
(các hàm helper) public:
CDate(int d=1, int m=1, int y=1) : ngay(d), thang(m), nam(y) {}
// Prefix ++a
CDate& operator++() {
// ... (logic tăng ngày) return
*this;
}
// Postfix a++
CDate operator++(int) {
CDate temp = *this;
++(*this);
return temp;
}
friend std::istream& operator>>(std::istream& is, CDate& d); friend std::ostream&
operator<<(std::ostream& os, const CDate& d); };
Câu 7: Thiết lp lp PhanSo... #include <iostream>
class PhanSo { private:
int tuSo, mauSo; public:
void nhap() { /* ... */ } void
xuat() const { /* ... */ }
PhanSo cong(const PhanSo& other) const { /* ... */ }
lO MoARcPSD|45467232
PhanSo tru(const PhanSo& other) const { /* ... */ }
PhanSo nhan(const PhanSo& other) const { /* ... */ }
PhanSo chia(const PhanSo& other) const { /* ... */ }
};
Câu 8: y dng lp biu din khái nim s phc...
#include <iostream> #include
<cmath> // for abs
class SoPhuc { private:
double thuc, ao; public:
void nhap() { /* ... */ } void
xuat() const { /* ... */ }
SoPhuc cong(const SoPhuc& other) const { /* ... */ }
SoPhuc tru(const SoPhuc& other) const { /* ... */ }
SoPhuc nhan(const SoPhuc& other) const { /* ... */ }
SoPhuc chia(const SoPhuc& other) const { /* ... */ }
};
Câu 9: y dng lp Candidate...
#include <iostream>
#include <string>
#include <vector> #include
<limits>
class Candidate { private:
std::string ma, ten, ngaySinh; float
diemToan, diemVan, diemAnh; public:
lO MoARcPSD|45467232
void nhap() { /* ... */ } void
xuat() const { /* ... */ }
float tongDiem() const { return diemToan + diemVan + diemAnh; }
};
class TestCandidate {
public: void kiemTra() {
int n;
std::cout << "Nhap so luong thi sinh: ";
std::cin >> n; std::vector<Candidate>
danhSach(n);
// ... (nhp và x lý danh sách)
}
};

Preview text:

lO M oARcPSD| 45467232
Đáp án Ôn tập Lập trình Hướng đối tượng Phần 1: Lý thuyết
Câu 1: Nêu khái niệm về sự kế thừa và những ưu nhược điểm của kế thừa trong việc lập
trình. Trường hợp nào thì có thể vi phạm tính kế thừa? Cho ví dụ minh họa.
Khái niệm: Kế thừa (Inheritance) là một trong bốn tính chất trụ cột của lập
trình hướng đối tượng (OOP). Nó cho phép một lớp (gọi là lớp con hoặc lớp
dẫn xuất) thừa hưởng lại các thuộc tính (dữ liệu) và phương thức (hành vi)
từ một lớp khác (gọi là lớp cha hoặc lớp cơ sở). • Ưu điểm:
o Tái sử dụng mã: Không cần phải viết lại code đã có ở lớp cha.
o Dễ bảo trì và mở rộng: Khi cần thay đổi, chỉ cần sửa ở lớp cha, các lớp con sẽ
tự động được cập nhật. Dễ dàng thêm các lớp con mới với các chức năng riêng biệt.
o Tạo ra một hệ thống phân cấp logic: Phản ánh mối quan hệ "is-a" (là một loại
của) trong thế giới thực, giúp code dễ hiểu hơn. •
Nhược điểm: o Liên kết chặt chẽ: Lớp con và lớp cha bị phụ thuộc lẫn
nhau. Sự thay đổi ở lớp cha có thể gây ra lỗi ở lớp con.
o Phức tạp hóa thiết kế: Hệ thống kế thừa đa tầng có thể trở nên phức tạp và khó quản lý. •
Trường hợp vi phạm tính kế thừa: Xảy ra khi mối quan hệ giữa lớp con và
lớp cha không phải là quan hệ "is-a". Điều này vi phạm nguyên tắc thay thế
Liskov (Liskov Substitution Principle). •
Ví dụ minh họa: Lớp HinhVuong kế thừa từ HinhChuNhat. Một hình chữ
nhật có thể thay đổi chiều dài và chiều rộng một cách độc lập, nhưng hình
vuông thì không (thay đổi một cạnh phải thay đổi cạnh còn lại). Điều này
phá vỡ hành vi của lớp cha. class HinhChuNhat { protected: • double chieuDai; • double chieuRong; • public: •
virtual void setChieuDai(double dai) { this->chieuDai = dai; } •
virtual void setChieuRong(double rong) { this->chieuRong = rong;} •
double tinhDienTich() const { return chieuDai * chieuRong; } • }; lO M oARcPSD| 45467232 •
// Vi phạm: Hình vuông không thể có chiều dài, rộng độc lập •
class HinhVuong : public HinhChuNhat { public: • void setCanh(double canh) { • this->chieuDai = canh; • this->chieuRong = canh; • } •
// Ghi đè lại để thay đổi hành vi, vi phạm nguyên tắc Liskov •
void setChieuDai(double dai) override { setCanh(dai); } •
void setChieuRong(double rong) override { setCanh(rong); } • };
Câu 2: Nêu khái niệm về trừu tượng hóa và những ưu nhược điểm của trừu tượng hóa
trong việc lập trình. Cho ví dụ minh họa.
Khái niệm: Trừu tượng hóa (Abstraction) là quá trình che giấu các chi tiết
cài đặt phức tạp và chỉ hiển thị các chức năng cần thiết ra bên ngoài. Nó tập
trung vào "cái gì" đối tượng có thể làm, thay vì "làm như thế nào". • Ưu điểm:
o Giảm độ phức tạp: Người dùng không cần quan tâm đến cách hoạt động bên trong.
o Tăng tính bảo mật: Che giấu các dữ liệu quan trọng.
o Dễ dàng thay đổi: Có thể thay đổi cách cài đặt bên trong mà không ảnh
hưởng đến code sử dụng lớp đó. • Nhược điểm:
o Thiết kế một giao diện trừu tượng tốt có thể khó và tốn thời gian. •
Ví dụ minh họa: Khi lái xe, bạn chỉ cần biết dùng vô lăng, chân ga, chân
phanh mà không cần biết động cơ, hộp số bên trong hoạt động ra sao.
Trong C++, lớp trừu tượng và hàm thuần ảo là công cụ chính để thực hiện. •
// Lớp trừu tượng "DongVat" • class DongVat { public: •
// Giao diện chung, không cần biết chi tiết cài đặt lO M oARcPSD| 45467232 •
virtual void keu() = 0; // Hàm thuần ảo • }; •
// Lớp cụ thể cài đặt chi tiết class Meo : public DongVat { public: • void keu() override { •
// Cài đặt cụ thể cho Mèo •
// std::cout << "Meow meow"; • } • };
Câu 3: Nêu khái niệm về đa hình và những ưu nhược điểm của đa hình trong việc lập
trình. Cho ví dụ minh họa.
Khái niệm: Đa hình (Polymorphism) cho phép một đối tượng có thể thể
hiện dưới nhiều hình thái khác nhau. Trong C++, nó thường có nghĩa là một
lời gọi hàm có thể thực thi các hành động khác nhau tùy thuộc vào kiểu đối
tượng tại thời điểm chạy (đa hình động). • Ưu điểm:
o Linh hoạt và mở rộng: Dễ dàng thêm các lớp mới mà không cần sửa đổi code hiện có.
o Code gọn gàng, dễ đọc: Viết code tổng quát xử lý được nhiều loại đối tượng khác nhau. • Nhược điểm:
o Khó theo dõi luồng chương trình: Vì hành vi cụ thể chỉ được xác định tại thời điểm chạy.
o Hiệu suất: Liên kết động có thể chậm hơn một chút so với liên kết tĩnh do cần
tra cứu trong bảng hàm ảo (vtable). • Ví dụ minh họa: • #include • class DongVat { public: lO M oARcPSD| 45467232 •
virtual void keu() { std::cout << "Tieng keu dong vat!" << std::endl; } •
virtual ~DongVat() {} // Luôn có hàm hủy ảo cho lớp cơ sở • }; • class Meo : public DongVat { public: •
void keu() override { std::cout << "Meow meow" << std::endl; } • }; • class Cho : public DongVat { public: •
void keu() override { std::cout << "Gau gau" << std::endl; } • }; •
void ngheTiengKeu(DongVat* dv) { •
dv->keu(); // Cùng một lời gọi, nhưng hành động khác nhau • } • int main() { • Meo conMeo; • Cho conCho; •
ngheTiengKeu(&conMeo); // In ra "Meow meow" •
ngheTiengKeu(&conCho); // In ra "Gau gau" • return 0; • }
Câu 4: Nêu khái niệm về đóng gói và những ưu nhược điểm của đóng gói trong việc lập
trình. Trường hợp nào thì có thể vi phạm tính đóng gói? Cho ví dụ minh họa.
Khái niệm: Đóng gói (Encapsulation) là kỹ thuật kết hợp dữ liệu (thuộc tính)
và các phương thức xử lý dữ liệu đó vào trong một thể thống nhất gọi là
lớp (class). Nó cũng che giấu thông tin bên trong lớp, không cho phép truy
cập trực tiếp từ bên ngoài. lO M oARcPSD| 45467232 • Ưu điểm:
o Bảo mật dữ liệu: Ngăn chặn truy cập trái phép làm thay đổi dữ liệu.
o Dễ quản lý: Code được tổ chức gọn gàng trong các lớp.
o Linh hoạt: Có thể thay đổi cấu trúc dữ liệu bên trong mà không ảnh hưởng
đến phần còn lại của chương trình. •
Nhược điểm: o Tăng lượng code cần viết (ví dụ: các hàm get/set). •
Trường hợp vi phạm tính đóng gói:
o Khai báo thuộc tính của lớp là public.
o Lạm dụng hàm bạn (friend function) hoặc lớp bạn (friend class). •
Ví dụ minh họa: class TaiKhoanNganHang { private: •
// Dữ liệu được bảo vệ, không thể truy cập từ bên ngoài • double soDu; • public: •
// Cung cấp giao diện công khai để tương tác • void nopTien(double soTien) { • if (soTien > 0) { • soDu += soTien; • } • } • double xemSoDu() { • return soDu; • } • };
Câu 5: a. Phân biệt các phạm vi truy cập private, protected và public. b. Cho biết ý nghĩa và
mục đích của các hàm get/set trong một lớp
a. Phân biệt các phạm vi truy cập: lO M oARcPSD| 45467232
o public: Có thể truy cập từ bất cứ đâu (bên trong lớp, lớp con, và bên ngoài lớp).
o protected: Có thể truy cập từ bên trong lớp đó và các lớp con kế thừa từ nó.
Không thể truy cập từ bên ngoài.
o private: Chỉ có thể truy cập từ bên trong chính lớp đó. Lớp con cũng không thể truy cập. •
b. Ý nghĩa và mục đích của các hàm get/set:
o Mục đích: Cung cấp một giao diện công khai (public) để truy cập (get) và sửa
đổi (set) các thuộc tính private một cách có kiểm soát.
o Hàm get (Getter/Accessor): Dùng để lấy (đọc) giá trị của một thuộc tính.
o Hàm set (Setter/Mutator): Dùng để thiết lập (ghi) giá trị cho một thuộc tính.
Hàm này có thể chứa logic kiểm tra tính hợp lệ của dữ liệu trước khi gán.
Câu 6: a. Phân biệt khái niệm lớp và đối tượng trong lập trình hướng đối tượng. b. Trình
bày khái niệm đa hình trong lập trình hướng đối tượng. Cho ví dụ minh họa.
a. Phân biệt khái niệm lớp và đối tượng:
o Lớp (Class): Là một bản thiết kế, một khuôn mẫu. Nó định nghĩa các thuộc
tính và phương thức chung cho một loại đối tượng. Lớp không chiếm bộ nhớ.
o Đối tượng (Object): Là một thể hiện cụ thể của một lớp. Nó được tạo ra từ
lớp và có trạng thái (giá trị của các thuộc tính) và hành vi riêng. Đối tượng
chiếm vùng nhớ trên RAM.
o Ví dụ: SinhVien là lớp, còn sinhVienA và sinhVienB là các đối tượng cụ thể. •
b. Trình bày khái niệm đa hình: (Câu trả lời giống hệt Câu 3).
Câu 7: Phân biệt các kiểu kế thừa private, protected, public
Kiểu kế thừa quyết định phạm vi truy cập của các thành viên được kế thừa từ lớp cha trong lớp con: •
public inheritance (kế thừa công khai): o public của cha -> public của con.
o protected của cha -> protected của con.
o Thường dùng cho quan hệ "is-a" (là một loại của). Đây là kiểu phổ biến nhất. •
protected inheritance (kế thừa được bảo vệ): o public của cha -> protected của con.
o protected của cha -> protected của con. lO M oARcPSD| 45467232 •
private inheritance (kế thừa riêng tư): o public của cha -> private của con.
o protected của cha -> private của con.
o Thường dùng cho quan hệ "is-implemented-in-terms-of" (được cài đặt dựa trên).
Câu 8 & 10b: Trình bày các đặc điểm quan trọng của lập trình hướng đối tượng
Bốn đặc điểm (trụ cột) chính của lập trình hướng đối tượng là:
1. Tính trừu tượng (Abstraction): Che giấu sự phức tạp, chỉ đưa ra giao diện cần thiết.
2. Tính đóng gói (Encapsulation): Gói gọn dữ liệu và phương thức vào một lớp, che giấu dữ liệu.
3. Tính kế thừa (Inheritance): Cho phép lớp con thừa hưởng các đặc tính của lớp cha.
4. Tính đa hình (Polymorphism): Cho phép đối tượng có nhiều hình thái, một hành
động có thể được thực hiện khác nhau.
Câu 9 & 10a: Trình bày khái niệm của lớp cơ sở trừu tượng (abstract class). Lớp cơ sở
trừu tượng được cài đặt trong C++ như thế nào? Hàm thuần ảo là gì? Lớp trừu tượng là
gì? Cho ví dụ minh họa.

Hàm thuần ảo là gì? Là một hàm ảo (virtual function) không có phần định nghĩa
(thân hàm) trong lớp cơ sở và được gán bằng = 0. •
virtual void hamThuanAo() = 0; •
Lớp trừu tượng là gì? Là lớp chứa ít nhất một hàm thuần ảo.
o Đặc điểm: Không thể tạo đối tượng trực tiếp từ lớp trừu tượng.
o Mục đích: Dùng làm lớp cơ sở chung, định nghĩa một "giao kèo" (interface)
mà tất cả các lớp con không trừu tượng BẮT BUỘC phải tuân theo bằng cách
định nghĩa (override) lại tất cả các hàm thuần ảo. •
Cài đặt trong C++: Một lớp trong C++ trở thành lớp trừu tượng khi ta khai báo ít
nhất một hàm thuần ảo trong nó. • // Lớp trừu tượng • class HinhHoc { public: •
virtual float tinhDienTich() = 0; // Hàm thuần ảo • }; lO M oARcPSD| 45467232
class HinhTron : public HinhHoc { private: float banKinh; public: •
// Lớp con BẮT BUỘC phải định nghĩa lại hàm thuần ảo •
float tinhDienTich() override { return 3.14 * banKinh * banKinh; } • };
Câu 11: Phân biệt khái niệm overload (tải chồng) và override (ghi đè) trong lập trình
hướng đối tượng. Tiêu chí
Overloading (Tải chồng) Overriding (Ghi đè) Phạm vi Trong cùng một lớp
Giữa lớp cha và lớp con Tên hàm Giống nhau Giống nhau
Chữ ký hàm (Tham Khác nhau (về số lượng hoặc Giống hệt nhau số) kiểu)
Dùng virtual ở lớp cha và override (khuyến Từ khóa Không cần khích) ở lớp con
Đa hình tĩnh (liên kết lúc biên Loại đa hình dịch)
Đa hình động (liên kết lúc chạy)
Câu 12: Trình bày khái niệm Hàm bạn, lớp bạn. Ưu nhược điểm. Cho ví dụ minh họa.
Khái niệm: friend là một từ khóa trong C++ cho phép một hàm hoặc một lớp
("bạn") truy cập vào các thành viên private và protected của một lớp khác. • Ưu điểm:
o Hữu ích trong một số trường hợp đặc biệt như nạp chồng toán tử
(operator<<, operator>>) mà không thể là hàm thành viên. • Nhược điểm:
o Vi phạm tính đóng gói: Đây là nhược điểm lớn nhất vì nó phá vỡ nguyên tắc che giấu thông tin.
o Làm cho thiết kế trở nên kém trong sáng và khó bảo trì hơn nếu bị lạm dụng.
Câu 13: Nêu vai trò của hàm tạo (Constructor), hàm hủy (destructor) trong định nghĩa lớp.
Ưu nhược điểm của hai loại hàm này khi sử dụng trong kế thừa. Cho ví dụ minh họa. lO M oARcPSD| 45467232 • Vai trò:
o Hàm tạo (Constructor): Được tự động gọi khi một đối tượng được tạo ra.
Nhiệm vụ chính là khởi tạo các giá trị ban đầu cho các thuộc tính và cấp phát tài nguyên (nếu có).
o Hàm hủy (Destructor): Được tự động gọi khi một đối tượng sắp bị hủy.
Nhiệm vụ chính là dọn dẹp, giải phóng tài nguyên mà đối tượng đã cấp phát. • Trong kế thừa:
o Thứ tự gọi: Hàm tạo được gọi theo thứ tự từ lớp cha đến lớp con. Hàm hủy
được gọi theo thứ tự ngược lại, từ lớp con đến lớp cha.
o Lưu ý quan trọng: Hàm hủy của lớp cha phải là hàm ảo (virtual) nếu bạn có ý
định xóa một đối tượng của lớp con thông qua con trỏ lớp cha. Nếu không,
chỉ hàm hủy của lớp cha được gọi, gây ra rò rỉ tài nguyên. class Parent { public: •
virtual ~Parent() { /* Hàm hủy ảo là bắt buộc */ } • }; • class Child : public Parent { private: int* data; public: •
Child() { data = new int[10]; } •
~Child() { delete[] data; /* Giải phóng bộ nhớ của Child */ } • }; • int main() { Parent* p = new Child();
delete p; // Sẽ gọi hàm hủy của Child rồi đến Parent, không bị rò rỉ bộ nhớ • return 0; • }
Câu 14: Trình bày phép gán trong lập trình hướng đối tượng. Tại sao phải xây dựng phép
gán cho lớp? Cho ví dụ minh họa.
Khái niệm: Là việc nạp chồng toán tử gán (operator=). Nó cho phép sao chép nội
dung từ một đối tượng đã tồn tại sang một đối tượng khác cũng đã tồn tại. lO M oARcPSD| 45467232 •
Tại sao phải xây dựng? Trình biên dịch cung cấp một toán tử gán mặc định, thực
hiện sao chép nông (shallow copy). Điều này sẽ gây ra vấn đề nếu lớp chứa dữ liệu kiểu con trỏ:
o Sao chép nông: Cả hai đối tượng sẽ cùng trỏ đến một vùng nhớ. Khi một đối
tượng bị hủy, đối tượng còn lại sẽ trỏ đến vùng nhớ không hợp lệ.
o Giải pháp: Ta phải tự định nghĩa toán tử gán để thực hiện sao chép sâu
(deep copy), tức là cấp phát một vùng nhớ mới cho đối tượng được gán và
sao chép nội dung sang đó.
Câu 15: Trình bày kỹ thuật nạp chồng (overloading) trong các tình huống không lập trình
hướng đối tượng, trong lập trình hướng đối tượng và hàm bạn. Cho ví dụ minh họa.
Nạp chồng (overloading) là việc tạo ra nhiều hàm có cùng tên nhưng khác nhau về danh
sách tham số (số lượng hoặc kiểu) trong cùng một phạm vi. •
Hàm thông thường (không phải OOP): • int tinhTong(int a, int b); •
double tinhTong(double a, double b); •
Hàm thành viên (OOP): • class PhepToan { public: • int cong(int a, int b); lO M oARcPSD| 45467232
double cong(double a, double b); }; •
Hàm bạn: Có thể được nạp chồng như hàm thông thường.
Câu 16: Trình bày kỹ thuật đa năng hóa toán tử (nạp chồng toán tử) trong xây dựng một
lớp. So sánh với cách xây dựng hàm tính toán tương ứng với toán tử. Cho ví dụ minh họa.
Khái niệm: Là một dạng đặc biệt của nạp chồng hàm, cho phép các toán tử có sẵn
của C++ (như +, -, *, /, ==, <<, >>...) hoạt động với các đối tượng của lớp do người dùng định nghĩa. • So sánh:
o Nạp chồng toán tử: Cú pháp tự nhiên, dễ đọc: PhanSo kq = ps1 + ps2;
o Hàm tính toán: Cú pháp dài dòng hơn: PhanSo kq = ps1.cong(ps2);
Câu 17: Trình bày kỹ thuật liên kết động. Cho ví dụ minh họa.
Khái niệm: Còn gọi là liên kết muộn (late binding). Là quá trình xác định phiên bản
hàm cụ thể nào sẽ được thực thi tại thời điểm chạy (runtime), thay vì tại thời điểm biên dịch. •
Cơ chế: C++ thực hiện liên kết động thông qua hàm ảo (virtual)con trỏ/tham
chiếu
đến lớp cơ sở. •
Ví dụ minh họa: Xem lại ví dụ ở Câu 3: Đa hình. Lời gọi dv->keu() chính là ví dụ về liên kết động.
Câu 18: Trình bày toán tử (). Cho ví dụ minh họa.
Khái niệm: Nạp chồng toán tử gọi hàm (operator()). Nó cho phép một đối tượng
của lớp có thể được "gọi" như một hàm. Những lớp như vậy được gọi là functor
hoặc function object. • #include • class CongThem { private: int giaTriThem; public: •
CongThem(int v) : giaTriThem(v) {}
int operator()(int so) const { return so + giaTriThem; lO M oARcPSD| 45467232 • } • }; • int main() { • CongThem cong5(5); •
std::cout << cong5(10); // Gọi đối tượng như một hàm, kết quả là 15 • return 0; • }
Câu 19: Trình bày con trỏ hàm. Cho ví dụ minh họa.
Khái niệm: Là một biến lưu trữ địa chỉ của một hàm. Thông qua con trỏ hàm, ta
có thể gọi hàm mà nó đang trỏ tới. •
Cú pháp: kiểu_trả_về (*tên_con_trỏ)(danh_sách_tham_số); • #include •
int cong(int a, int b) { return a + b; } •
int tru(int a, int b) { return a - b; } • int main() { • int (*phepToan)(int, int); • phepToan = ≅ •
std::cout << "Tong: " << phepToan(5, 3) << std::endl; // 8 • phepToan = &tru; •
std::cout << "Hieu: " << phepToan(5, 3) << std::endl; // 2 • return 0; • }
Câu 20: So sánh hàm tạo sao chép và phép gán. Cho ví dụ minh họa. lO M oARcPSD| 45467232 Tiêu
Hàm tạo sao chép (Copy
Phép gán (Assignment Operator) chí Constructor)
Khởi tạo một đối tượng Sao chép dữ liệu từ một đối tượng
Mục đích mới từ một đối tượng đã đã có vào một đối tượng khác đã có. tồn tại.
Thời điểm MyClass obj2 = obj1; (Khai MyClass obj1, obj2; obj2 = obj1; gọi báo) (Gán)
Cần kiểm tra tự gán (if (this != Không cần kiểm tra tự gán. Lưu ý
&other)) để tránh lỗi. Phần 2: Bài tập
Câu 1: Xây dựng lớp đa thức bậc nhất... #include
class DaThucBacNhat { private: float a, b; // F(x) = ax + b public:
// Hàm tạo đảm bảo a != 0
DaThucBacNhat(float heSoA = 1.0, float heSoB = 0.0) : b(heSoB) { a = (heSoA == 0) ? 1 : heSoA; } // a. Tính giá trị F(x0)
double tinhGiaTri(double x0) const { return a * x0 + b; } lO M oARcPSD| 45467232
// b. Tìm nghiệm F(x) = 0 double timNghiem() const { return -b / a; } // c. Cộng hai đa thức
DaThucBacNhat operator+(const DaThucBacNhat& other) const { return
DaThucBacNhat(this->a + other.a, this->b + other.b); } void inDaThuc() const {
std::cout << a << "x + " << b << std::endl; } };
Câu 3: Xây dựng lớp đơn thức... #include #include class DonThuc { private: float a; // hệ số int n; // số mũ public:
DonThuc(float heSoA = 1.0, int soMuN = 1) { a = (heSoA == 0) ? 1 : heSoA;
n = (soMuN >= 1 && soMuN <= 100) ? soMuN : 1; } lO M oARcPSD| 45467232
// a. Tính giá trị F(x0) double
tinhGiaTri(double x0) const { return a * pow(x0, n); }
// b. Tính nghiệm F(x) = b void
timNghiem(double b_val) const {
// ... (logic xử lý nghiệm) }
// c. Cộng hai đơn thức void cong(const
DonThuc& other) const { if (this->n == other.n) {
// ... (cộng và in ra đơn thức tổng) } else {
// ... (in ra đa thức tổng) } } };
Câu 4: ...Hãy định nghĩa lớp cNgay thích hợp... #include using namespace std; class cNgay { private:
int ngay, thang, nam; public:
cNgay() : ngay(1), thang(1), nam(1) {} cNgay(int y, int m) : ngay(1),
thang(m), nam(y) {} cNgay(int y, int m, int d) : ngay(d), thang(m), nam(y) {} lO M oARcPSD| 45467232
bool operator<(const cNgay& other) const { if (nam !=
other.nam) return nam < other.nam; if (thang != other.thang)
return thang < other.thang; return ngay < other.ngay; }
friend istream& operator>>(istream& is, cNgay& obj); friend ostream&
operator<<(ostream& os, const cNgay& obj); };
istream& operator>>(istream& is, cNgay& obj) { /* ... */ return is; } ostream&
operator<<(ostream& os, const cNgay& obj) { /* ... */ return os; }
Câu 5: Cho lớp Phân số (CPhanSo)... #include
#include // Cho std::gcd using namespace std; class CPhanSo { private: int tuSo, mauSo; void
rutGon() { /* ... */ } public:
CPhanSo(int tu = 0, int mau = 1) : tuSo(tu), mauSo(mau) {}
CPhanSo operator+(const CPhanSo& other) const { /* ... */ } bool
operator==(const CPhanSo& other) const { /* ... */ }
friend CPhanSo operator+(const CPhanSo& ps, int x); friend CPhanSo
operator+(int x, const CPhanSo& ps); friend istream& operator>>(istream& is,
CPhanSo& ps); friend ostream& operator<<(ostream& os, const CPhanSo& ps); };
// ... (định nghĩa các hàm friend) lO M oARcPSD| 45467232
Câu 6: Định nghĩa lớp CDate... #include class CDate { private: int ngay, thang, nam; // ... (các hàm helper) public:
CDate(int d=1, int m=1, int y=1) : ngay(d), thang(m), nam(y) {} // Prefix ++a CDate& operator++() {
// ... (logic tăng ngày) return *this; } // Postfix a++ CDate operator++(int) { CDate temp = *this; ++(*this); return temp; }
friend std::istream& operator>>(std::istream& is, CDate& d); friend std::ostream&
operator<<(std::ostream& os, const CDate& d); };
Câu 7: Thiết lập lớp PhanSo... #include class PhanSo { private: int tuSo, mauSo; public:
void nhap() { /* ... */ } void xuat() const { /* ... */ }
PhanSo cong(const PhanSo& other) const { /* ... */ } lO M oARcPSD| 45467232
PhanSo tru(const PhanSo& other) const { /* ... */ }
PhanSo nhan(const PhanSo& other) const { /* ... */ }
PhanSo chia(const PhanSo& other) const { /* ... */ } };
Câu 8: Xây dựng lớp biểu diễn khái niệm số phức... #include #include // for abs class SoPhuc { private: double thuc, ao; public:
void nhap() { /* ... */ } void xuat() const { /* ... */ }
SoPhuc cong(const SoPhuc& other) const { /* ... */ }
SoPhuc tru(const SoPhuc& other) const { /* ... */ }
SoPhuc nhan(const SoPhuc& other) const { /* ... */ }
SoPhuc chia(const SoPhuc& other) const { /* ... */ } };
Câu 9: Xây dựng lớp Candidate... #include #include #include #include class Candidate { private:
std::string ma, ten, ngaySinh; float
diemToan, diemVan, diemAnh; public: lO M oARcPSD| 45467232
void nhap() { /* ... */ } void xuat() const { /* ... */ }
float tongDiem() const { return diemToan + diemVan + diemAnh; } }; class TestCandidate { public: void kiemTra() { int n;
std::cout << "Nhap so luong thi sinh: ";
std::cin >> n; std::vector danhSach(n);
// ... (nhập và xử lý danh sách) } };