fork download
  1. /*
  2. ================================================================================
  3.  BÀI TOÁN: QUẢN LÝ DANH SÁCH SẢN PHẨM
  4. ================================================================================
  5.  Mô tả:
  6.   Chương trình quản lý danh sách sản phẩm trong một cửa hàng bán lẻ.
  7.   Hệ thống hỗ trợ hai loại sản phẩm:
  8.   - SanPhamVatLy : sản phẩm có hình thức vật lý (điện thoại, laptop, ...)
  9.   - SanPhamKyThuat: sản phẩm kỹ thuật số / phần mềm (ứng dụng, game, ...)
  10.  
  11.   Chức năng chính:
  12.   1. Nhập danh sách sản phẩm từ bàn phím.
  13.   2. In toàn bộ danh sách sản phẩm.
  14.   3. Tìm kiếm sản phẩm theo tên.
  15.   4. Sắp xếp danh sách theo giá (tăng dần).
  16.   5. Tăng / giảm số lượng tồn kho bằng toán tử ++ / --.
  17.   6. Ghép hai danh sách sản phẩm bằng toán tử +.
  18.  
  19.  Yêu cầu OOP đã triển khai:
  20.   02. Tính đóng gói – dữ liệu private, truy cập qua getter/setter
  21.   03. Tính kế thừa – SanPhamVatLy & SanPhamKyThuat kế thừa SanPham
  22.   04. Tính đa hình – virtual hienThi(), tinhThue()
  23.   05. Tính trừu tượng – lớp trừu tượng SanPham (pure virtual)
  24.   06. Template – hàm timMax<T>() và lớp DanhSach<T>
  25.   07. Toán tử nhập/xuất – operator>> , operator<<
  26.   08. Toán tử ++ / -- – tăng / giảm soLuong
  27.   09. Toán tử + / - – ghép / lấy hiệu hai DanhSach
  28.   10. Hàm cấu tử rỗng – SanPham(), SanPhamVatLy(), SanPhamKyThuat()
  29.   11. Hàm cấu tử đầy đủ – SanPham(...), SanPhamVatLy(...), SanPhamKyThuat(...)
  30.   12. Main – nhập danh sách
  31.   13. Main – in danh sách
  32.   14. Main – sắp xếp, tìm kiếm
  33. ================================================================================
  34. */
  35.  
  36. #include <iostream>
  37. #include <string>
  38. #include <vector>
  39. #include <algorithm>
  40. #include <iomanip>
  41. #include <stdexcept>
  42. #include <functional>
  43.  
  44. using namespace std;
  45.  
  46. class SanPham {
  47. protected:
  48. string maSP;
  49. string tenSP;
  50. double gia;
  51. int soLuong;
  52.  
  53. public:
  54. // Cấu tử rỗng (Default Constructor)
  55. SanPham() : maSP(""), tenSP(""), gia(0.0), soLuong(0) {}
  56.  
  57. // Cấu tử đầy đủ tham số (Parameterized Constructor)
  58. SanPham(const string& ma, const string& ten, double g, int sl)
  59. : maSP(ma), tenSP(ten), gia(g), soLuong(sl) {}
  60.  
  61. // Hàm hủy ảo (Virtual Destructor) để tránh rò rỉ bộ nhớ khi giải phóng con trỏ đa hình
  62. virtual ~SanPham() {}
  63.  
  64. // Các hàm Getter và Setter giúp đảm bảo tính đóng gói
  65. string getMa() const { return maSP; }
  66. string getTen() const { return tenSP; }
  67. double getGia() const { return gia; }
  68. int getSoLuong() const { return soLuong; }
  69. void setGia(double g) { if (g >= 0) gia = g; }
  70. void setSoLuong(int sl){ if (sl >= 0) soLuong = sl; }
  71.  
  72. // Các hàm thuần ảo (Pure Virtual Functions) bắt buộc các lớp con phải override
  73. virtual void hienThi() const = 0;
  74. virtual double tinhThue() const = 0;
  75. virtual string loaiSP() const = 0;
  76.  
  77. // Nạp chồng toán tử tăng/giảm (++ / -- prefix) để thay đổi số lượng tồn kho
  78. SanPham& operator++() { ++soLuong; return *this; }
  79. SanPham& operator--() { if (soLuong > 0) --soLuong; return *this; }
  80.  
  81. // Nạp chồng toán tử xuất (operator<<) sử dụng tính đa hình để gọi hàm hienThi()
  82. friend ostream& operator<<(ostream& os, const SanPham& sp) {
  83. sp.hienThi();
  84. return os;
  85. }
  86.  
  87. // Nạp chồng toán tử nhập (operator>>) để nhập các thông tin cơ bản của sản phẩm
  88. friend istream& operator>>(istream& is, SanPham& sp) {
  89. cout << " Ma SP : "; getline(is, sp.maSP);
  90. cout << " Ten SP : "; getline(is, sp.tenSP);
  91. cout << " Gia (VND) : "; is >> sp.gia; is.ignore();
  92. cout << " So luong : "; is >> sp.soLuong; is.ignore();
  93. return is;
  94. }
  95. };
  96.  
  97.  
  98. // ============================================================================
  99. // GIẢI THÍCH: LỚP SAN PHAM VAT LY KẾ THỪA (INHERITANCE) TỪ SAN PHAM
  100. // - Mở rộng thêm 2 thuộc tính: trongLuong và xuatXu.
  101. // - Đa hình (Polymorphism): Ghi đè (override) hàm tính thuế và hiển thị riêng cho đồ vật lý.
  102. // ============================================================================
  103. class SanPhamVatLy : public SanPham {
  104. private:
  105. double trongLuong;
  106. string xuatXu;
  107.  
  108. public:
  109. // Cấu tử rỗng gọi cấu tử rỗng của lớp cha
  110. SanPhamVatLy() : SanPham(), trongLuong(0.0), xuatXu("") {}
  111.  
  112. // Cấu tử đầy đủ sử dụng Member Initializer List để truyền dữ liệu lên lớp cha
  113. SanPhamVatLy(const string& ma, const string& ten, double g, int sl, double tl, const string& xx)
  114. : SanPham(ma, ten, g, sl), trongLuong(tl), xuatXu(xx) {}
  115.  
  116. string loaiSP() const override { return "Vat Ly"; }
  117.  
  118. // Triển khai quy tắc tính thuế riêng: Xuất xứ nước ngoài chịu thuế 10%, Việt Nam 5%
  119. double tinhThue() const override {
  120. return (xuatXu != "Viet Nam") ? gia * 0.10 : gia * 0.05;
  121. }
  122.  
  123. // Định dạng bảng hiển thị thông tin sản phẩm vật lý ra màn hình
  124. void hienThi() const override {
  125. cout << fixed << setprecision(0);
  126. cout << " [VAT LY] " << maSP
  127. << " | " << left << setw(24) << tenSP
  128. << " | Gia: " << right << setw(12) << gia
  129. << " | SL: " << setw(4) << soLuong
  130. << " | " << trongLuong << "kg | " << xuatXu
  131. << " | Thue: " << tinhThue() << "\n";
  132. }
  133.  
  134. // Nạp chồng toán tử nhập riêng, tận dụng toán tử nhập của lớp cha (ép kiểu static_cast)
  135. friend istream& operator>>(istream& is, SanPhamVatLy& sp) {
  136. is >> static_cast<SanPham&>(sp);
  137. cout << " Trong luong(kg): "; is >> sp.trongLuong; is.ignore();
  138. cout << " Xuat xu : "; getline(is, sp.xuatXu);
  139. return is;
  140. }
  141. };
  142.  
  143.  
  144. // ============================================================================
  145. // GIẢI THÍCH: LỚP SAN PHAM KY THUAT KẾ THỪA TỪ SAN PHAM
  146. // - Quản lý các mặt hàng số, phần mềm với thuộc tính riêng: phienBan, nhaPhat, coGiayPhep.
  147. // - Triển khai quy tắc thuế VAT cố định 8% cho phần mềm.
  148. // ============================================================================
  149. class SanPhamKyThuat : public SanPham {
  150. private:
  151. string phienBan;
  152. string nhaPhat;
  153. bool coGiayPhep;
  154.  
  155. public:
  156. // Cấu tử rỗng
  157. SanPhamKyThuat() : SanPham(), phienBan("1.0"), nhaPhat(""), coGiayPhep(false) {}
  158.  
  159. // Cấu tử đầy đủ tham số
  160. SanPhamKyThuat(const string& ma, const string& ten, double g, int sl, const string& pv, const string& np, bool cgp)
  161. : SanPham(ma, ten, g, sl), phienBan(pv), nhaPhat(np), coGiayPhep(cgp) {}
  162.  
  163. string loaiSP() const override { return "Ky Thuat So"; }
  164.  
  165. // Thuế sản phẩm số mặc định là 8% giá bán
  166. double tinhThue() const override {
  167. return gia * 0.08;
  168. }
  169.  
  170. // Định dạng hiển thị thông tin sản phẩm kỹ thuật số
  171. void hienThi() const override {
  172. cout << fixed << setprecision(0);
  173. cout << " [KY THUAT] " << maSP
  174. << " | " << left << setw(24) << tenSP
  175. << " | Gia: " << right << setw(12) << gia
  176. << " | SL: " << setw(4) << soLuong
  177. << " | v" << phienBan
  178. << " | " << nhaPhat
  179. << " | GiayPhep: " << (coGiayPhep ? "Co" : "Khong")
  180. << " | Thue: " << tinhThue() << "\n";
  181. }
  182.  
  183. // Nạp chồng toán tử nhập cho các thuộc tính đặc thù của sản phẩm số
  184. friend istream& operator>>(istream& is, SanPhamKyThuat& sp) {
  185. is >> static_cast<SanPham&>(sp);
  186. cout << " Phien ban : "; getline(is, sp.phienBan);
  187. cout << " Nha phat : "; getline(is, sp.nhaPhat);
  188. cout << " Co giay phep (1/0): "; is >> sp.coGiayPhep; is.ignore();
  189. return is;
  190. }
  191. };
  192.  
  193.  
  194. // ============================================================================
  195. // GIẢI THÍCH: HÀM MẪU (FUNCTION TEMPLATE) TIMMAX
  196. // - Hàm tổng quát cho phép tìm kiếm phần tử lớn nhất trong một vector bất kỳ.
  197. // - Sử dụng con trỏ hàm/biểu thức Lambda (`soSanh`) để tăng tính linh hoạt khi so sánh.
  198. // ============================================================================
  199. template <typename T>
  200. T timMax(const vector<T>& ds, function<bool(const T&, const T&)> soSanh) {
  201. if (ds.empty()) throw runtime_error("Danh sach rong!");
  202. T maxVal = ds[0];
  203. for (const auto& item : ds)
  204. if (soSanh(maxVal, item)) maxVal = item;
  205. return maxVal;
  206. }
  207.  
  208.  
  209. // ============================================================================
  210. // GIẢI THÍCH: LỚP MẪU (CLASS TEMPLATE) DANH SACH
  211. // - Lưu trữ mảng các con trỏ kiểu `T*`. Giúp quản lý danh sách đa hình (SanPham*).
  212. // - Chứa toàn bộ các hàm chức năng: Thêm, In, Sắp xếp, Tìm kiếm, Thống kê dữ liệu.
  213. // ============================================================================
  214. template <typename T>
  215. class DanhSach {
  216. private:
  217. vector<T*> ds; // Vector lưu trữ danh sách các con trỏ đối tượng
  218.  
  219. public:
  220. DanhSach() {}
  221. ~DanhSach() {}
  222.  
  223. // Thêm một con trỏ sản phẩm mới vào danh sách
  224. void them(T* sp) { ds.push_back(sp); }
  225.  
  226. // Lấy số lượng sản phẩm hiện tại trong danh sách
  227. int kichThuoc() const { return (int)ds.size(); }
  228.  
  229. // Truy xuất đến phần tử thứ i (có kiểm tra an toàn chỉ số mảng)
  230. T* layPhanTu(int i) const {
  231. if (i < 0 || i >= (int)ds.size()) throw out_of_range("Chi so ngoai pham vi!");
  232. return ds[i];
  233. }
  234.  
  235. // Duyệt danh sách và xuất thông tin từng sản phẩm dựa trên toán tử << đã nạp chồng
  236. void inDanhSach() const {
  237. if (ds.empty()) { cout << " (Danh sach trong)\n"; return; }
  238. for (const auto& p : ds) cout << *p;
  239. }
  240.  
  241. // Thuật toán Bubble Sort dùng để sắp xếp các con trỏ sản phẩm theo giá tăng dần
  242. void sapXepTheoGia() {
  243. int n = (int)ds.size();
  244. for (int i = 0; i < n - 1; i++)
  245. for (int j = 0; j < n - i - 1; j++)
  246. if (ds[j]->getGia() > ds[j+1]->getGia())
  247. swap(ds[j], ds[j+1]);
  248. }
  249.  
  250. // Tìm kiếm sản phẩm theo tên (đã chuẩn hóa về chữ thường để không phân biệt Hoa/Thường)
  251. vector<T*> timKiemTheoTen(const string& ten) const {
  252. vector<T*> ketQua;
  253. string tenLower = ten;
  254. transform(tenLower.begin(), tenLower.end(), tenLower.begin(), ::tolower);
  255. for (auto p : ds) {
  256. string t = p->getTen();
  257. transform(t.begin(), t.end(), t.begin(), ::tolower);
  258. if (t.find(tenLower) != string::npos)
  259. ketQua.push_back(p);
  260. }
  261. return ketQua;
  262. }
  263.  
  264. // Hàm tính toán tổng tiền hàng tồn kho (Giá sản phẩm * Số lượng tương ứng)
  265. double tongGiaTriTonKho() const {
  266. double tong = 0;
  267. for (auto p : ds) tong += p->getGia() * p->getSoLuong();
  268. return tong;
  269. }
  270.  
  271. // Toán tử +: Ghép nối (gộp) hai danh sách sản phẩm lại với nhau
  272. DanhSach<T> operator+(const DanhSach<T>& other) const {
  273. DanhSach<T> result;
  274. for (auto p : ds) result.ds.push_back(p);
  275. for (auto p : other.ds) result.ds.push_back(p);
  276. return result;
  277. }
  278.  
  279. // Toán tử -: Loại bỏ các sản phẩm ở danh sách bên trái nếu bị trùng mã SP với danh sách bên phải
  280. DanhSach<T> operator-(const DanhSach<T>& other) const {
  281. DanhSach<T> result;
  282. for (auto p : ds) {
  283. bool thuocOther = false;
  284. for (auto q : other.ds)
  285. if (p->getMa() == q->getMa()) { thuocOther = true; break; }
  286. if (!thuocOther) result.ds.push_back(p);
  287. }
  288. return result;
  289. }
  290.  
  291. // Nạp chồng toán tử xuất cho cả một Danh Sách dữ liệu giúp rút ngắn câu lệnh in ở main
  292. friend ostream& operator<<(ostream& os, const DanhSach<T>& dl) {
  293. for (const auto& p : dl.ds) os << *p;
  294. return os;
  295. }
  296. };
  297.  
  298.  
  299. // ============================================================================
  300. // GIẢI THÍCH: HÀM TRỢ GIÚP IN TIÊU ĐỀ
  301. // Tách biệt các phân đoạn chức năng trên màn hình console để giao diện trực quan hơn.
  302. // ============================================================================
  303. void inTieuDe(const string& tieu) {
  304. cout << "\n" << string(70, '=') << "\n";
  305. cout << " " << tieu << "\n";
  306. cout << string(70, '=') << "\n";
  307. }
  308.  
  309.  
  310. // ============================================================================
  311. // GIẢI THÍCH: HÀM MAIN - ĐIỀU KHIỂN CHƯƠNG TRÌNH CHÍNH
  312. // Thực hiện gọi tuần tự các chức năng: Nhập, Xuất danh sách, Demo toán tử ++/--,
  313. // Sắp xếp tăng dần, Tìm kiếm theo từ khóa, Thống kê tổng tiền, Sử dụng Hàm mẫu timMax,
  314. // và thực hiện gộp hai danh sách bằng toán tử +.
  315. // ============================================================================
  316. int main() {
  317. system("chcp 65001 > nul"); // Thiết lập bảng mã UTF-8 để console hiển thị tiếng Việt mượt mà
  318. cout << "================================================\n";
  319. cout << " QUAN LY DANH SACH SAN PHAM – OOP C++\n";
  320. cout << "================================================\n";
  321.  
  322. DanhSach<SanPham> danhSach;
  323.  
  324. // --- CHỨC NĂNG 1: NHẬP DANH SÁCH SẢN PHẨM PHÂN LOẠI ---
  325. inTieuDe("NHAP DANH SACH SAN PHAM");
  326. int n;
  327. cout << "So luong san pham can nhap: ";
  328. cin >> n; cin.ignore();
  329.  
  330. for (int i = 0; i < n; i++) {
  331. cout << "\n--- San pham " << i+1 << " ---\n";
  332. cout << " Loai (1 = Vat Ly / 2 = Ky Thuat So): ";
  333. int loai; cin >> loai; cin.ignore();
  334.  
  335. if (loai == 1) {
  336. SanPhamVatLy* sp = new SanPhamVatLy();
  337. cin >> *sp;
  338. danhSach.them(sp);
  339. } else {
  340. SanPhamKyThuat* sp = new SanPhamKyThuat();
  341. cin >> *sp;
  342. danhSach.them(sp);
  343. }
  344. }
  345.  
  346. // --- CHỨC NĂNG 2: IN DANH SÁCH GỐC VỪA NHẬP ---
  347. inTieuDe("DANH SACH SAN PHAM DA NHAP");
  348. danhSach.inDanhSach();
  349.  
  350. // --- CHỨC NĂNG 3: MINH HỌA TOÁN TỬ TĂNG GIẢM (++ / --) TỒN KHO ---
  351. inTieuDe("DEMO TOAN TU ++ VA --");
  352. if (danhSach.kichThuoc() > 0) {
  353. SanPham* sp0 = danhSach.layPhanTu(0);
  354. cout << " Truoc ++: SL = " << sp0->getSoLuong() << "\n";
  355. ++(*sp0);
  356. cout << " Sau ++: SL = " << sp0->getSoLuong() << "\n";
  357. --(*sp0);
  358. cout << " Sau --: SL = " << sp0->getSoLuong() << "\n";
  359. }
  360.  
  361. // --- CHỨC NĂNG 4: SẮP XẾP SẢN PHẨM THEO GIÁ TĂNG DẦN ---
  362. inTieuDe("DANH SACH SAU KHI SAP XEP THEO GIA TANG DAN");
  363. danhSach.sapXepTheoGia();
  364. danhSach.inDanhSach();
  365.  
  366. // --- CHỨC NĂNG 5: TÌM KIẾM THEO TÊN SẢN PHẨM ---
  367. inTieuDe("TIM KIEM SAN PHAM THEO TEN");
  368. cout << " Nhap tu khoa tim kiem: ";
  369. string tuKhoa; getline(cin, tuKhoa);
  370.  
  371. auto ketQua = danhSach.timKiemTheoTen(tuKhoa);
  372. if (ketQua.empty()) {
  373. cout << " Khong tim thay san pham nao!\n";
  374. } else {
  375. cout << " Tim thay " << ketQua.size() << " san pham:\n";
  376. for (auto p : ketQua) cout << *p;
  377. }
  378.  
  379. // --- CHỨC NĂNG 6: THỐNG KÊ TỔNG GIÁ TRỊ TỒN KHO ---
  380. inTieuDe("THONG KE");
  381. cout << fixed << setprecision(0);
  382. cout << " Tong gia tri ton kho: " << danhSach.tongGiaTriTonKho() << " VND\n";
  383.  
  384. // --- CHỨC NĂNG 7: SỬ DỤNG HÀM MẪU TEMPLATE ĐỂ TÌM GIÁ CAO NHẤT ---
  385. inTieuDe("SAN PHAM CO GIA CAO NHAT (template timMax)");
  386. vector<double> dsGia;
  387. for (int i = 0; i < danhSach.kichThuoc(); i++)
  388. dsGia.push_back(danhSach.layPhanTu(i)->getGia());
  389.  
  390. if (!dsGia.empty()) {
  391. double maxGia = timMax<double>(dsGia, [](const double& a, const double& b){ return a < b; });
  392. cout << " Gia cao nhat trong danh sach: " << maxGia << " VND\n";
  393. }
  394.  
  395. // --- CHỨC NĂNG 8: MINH HỌA TOÁN TỬ + ĐỂ GỘP HAI DANH SÁCH ---
  396. inTieuDe("DEMO TOAN TU + (ghep danh sach)");
  397. DanhSach<SanPham> ds1, ds2;
  398. ds1.them(new SanPhamVatLy("SP100","Ban phim co", 850000, 10, 0.5,"Viet Nam"));
  399. ds2.them(new SanPhamKyThuat("SP200","Phan mem diet virus", 299000, 50,"3.1","Kaspersky",true));
  400.  
  401. cout << " Danh sach 1:\n"; ds1.inDanhSach();
  402. cout << " Danh sach 2:\n"; ds2.inDanhSach();
  403.  
  404. cout << " Ket qua ghep (ds1 + ds2):\n";
  405. cout << ds1 + ds2;
  406.  
  407. cout << "\n" << string(70, '=') << "\n";
  408. cout << " Chuong trinh ket thuc. Cam on!\n";
  409. cout << string(70, '=') << "\n";
  410.  
  411. return 0;
  412. }
  413.  
Success #stdin #stdout #stderr 0.01s 5320KB
stdin
Standard input is empty
stdout
================================================
   QUAN LY DANH SACH SAN PHAM – OOP C++
================================================

======================================================================
  NHAP DANH SACH SAN PHAM
======================================================================
So luong san pham can nhap: 
======================================================================
  DANH SACH SAN PHAM DA NHAP
======================================================================
  (Danh sach trong)

======================================================================
  DEMO TOAN TU ++ VA --
======================================================================

======================================================================
  DANH SACH SAU KHI SAP XEP THEO GIA TANG DAN
======================================================================
  (Danh sach trong)

======================================================================
  TIM KIEM SAN PHAM THEO TEN
======================================================================
  Nhap tu khoa tim kiem:   Khong tim thay san pham nao!

======================================================================
  THONG KE
======================================================================
  Tong gia tri ton kho: 0 VND

======================================================================
  SAN PHAM CO GIA CAO NHAT (template timMax)
======================================================================

======================================================================
  DEMO TOAN TU + (ghep danh sach)
======================================================================
  Danh sach 1:
  [VAT LY] SP100 | Ban phim co              | Gia:       850000 | SL:   10 | 0kg | Viet Nam | Thue: 42500
  Danh sach 2:
  [KY THUAT] SP200 | Phan mem diet virus      | Gia:       299000 | SL:   50 | v3.1 | Kaspersky | GiayPhep: Co | Thue: 23920
  Ket qua ghep (ds1 + ds2):
  [VAT LY] SP100 | Ban phim co              | Gia:       850000 | SL:   10 | 0kg | Viet Nam | Thue: 42500
  [KY THUAT] SP200 | Phan mem diet virus      | Gia:       299000 | SL:   50 | v3.1 | Kaspersky | GiayPhep: Co | Thue: 23920

======================================================================
  Chuong trinh ket thuc. Cam on!
======================================================================
stderr
sh: 1: cannot create nul: Permission denied
sh: 1: chcp: not found