


















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) và 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) } };