Bài 35.5: Bài tập thực hành lập trình hướng đối tượng trong C++

Bài 35.5: Bài tập thực hành lập trình hướng đối tượng trong C++
Bài tập 1: Quản lý Sinh viên - Lớp SinhVien
Yêu cầu:
- Tạo một lớp
SinhVien
với các thuộc tính nhưmaSV
(string),tenSV
(string), vàdiemTB
(double). - Lớp này cần có các phương thức để:
- Thiết lập và lấy giá trị của các thuộc tính.
- Hiển thị thông tin sinh viên.
- Trong hàm
main
, tạo một vài đối tượngSinhVien
, thiết lập giá trị cho chúng và hiển thị thông tin.
#include <iostream>
#include <string>
#include <iomanip>
class SinhVien {
private:
string maSV;
string tenSV;
double diemTB;
public:
SinhVien(string ma, string ten, double diem) : maSV(ma), tenSV(ten), diemTB(diem) {
cout << "Da tao sinh vien: " << tenSV << endl;
}
~SinhVien() {
}
void setMaSV(const string& ma) {
maSV = ma;
}
void setTenSV(const string& ten) {
tenSV = ten;
}
void setDiemTB(double diem) {
if (diem >= 0 && diem <= 10) {
diemTB = diem;
} else {
cerr << "Loi: Diem khong hop le!" << endl;
}
}
string getMaSV() const {
return maSV;
}
string getTenSV() const {
return tenSV;
}
double getDiemTB() const {
return diemTB;
}
void hien() const {
cout << "--- Thong tin Sinh vien ---" << endl;
cout << "Ma SV: " << maSV << endl;
cout << "Ten SV: " << tenSV << endl;
cout << "Diem TB: " << fixed << setprecision(2) << diemTB << endl;
cout << "--------------------------" << endl;
}
};
int main() {
SinhVien sv1("SV001", "Nguyen Van A", 8.75);
sv1.hien();
sv1.setDiemTB(9.0);
cout << "\nCap nhat diem cho " << sv1.getTenSV() << endl;
sv1.hien();
SinhVien sv2("SV002", "Tran Thi B", 7.5);
sv2.hien();
return 0;
}
Output:
Da tao sinh vien: Nguyen Van A
--- Thong tin Sinh vien ---
Ma SV: SV001
Ten SV: Nguyen Van A
Diem TB: 8.75
--------------------------
Cap nhat diem cho Nguyen Van A
--- Thong tin Sinh vien ---
Ma SV: SV001
Ten SV: Nguyen Van A
Diem TB: 9.00
--------------------------
Da tao sinh vien: Tran Thi B
--- Thong tin Sinh vien ---
Ma SV: SV002
Ten SV: Tran Thi B
Diem TB: 7.50
--------------------------
Bài tập 2: Tương tác giữa các đối tượng - Lớp Sach
và ThuVien
Yêu cầu:
- Tạo một lớp
Sach
đơn giản với các thuộc tính nhưtieuDe
(string) vàtacGia
(string), và một phương thức hiển thị thông tin sách. - Tạo một lớp
ThuVien
. Lớp này sẽ chứa một tập hợp các đối tượngSach
. Sử dụngvector
để lưu trữ danh sách sách. - Lớp
ThuVien
cần có các phương thức để:- Thêm một cuốn sách vào thư viện.
- Hiển thị thông tin của tất cả các cuốn sách trong thư viện.
Giải thích:
Bài tập này minh họa mối quan hệ thành phần (composition) trong OOP, nơi một đối tượng của lớp này (ThuVien
) có chứa (has-a) các đối tượng của lớp khác (Sach
). Bạn sẽ thấy cách các đối tượng tương tác với nhau thông qua việc gọi các phương thức của nhau.
Code minh họa:
#include <iostream>
#include <string>
#include <vector>
class Sach {
private:
string td;
string tg;
public:
Sach(string tieuDe, string tacGia) : td(tieuDe), tg(tacGia) {}
string getTD() const { return td; }
string getTG() const { return tg; }
void hien() const {
cout << "- \"" << td << "\" by " << tg << endl;
}
};
class ThuVien {
private:
vector<Sach> ds;
public:
void them(const Sach& s) {
ds.push_back(s);
cout << "Da them sach: \"" << s.getTD() << "\"" << endl;
}
void hienTatCa() const {
cout << "\n--- Cac sach trong thu vien ---" << endl;
if (ds.empty()) {
cout << "Thu vien hien tai rong." << endl;
} else {
for (const auto& s : ds) {
s.hien();
}
}
cout << "------------------------------" << endl;
}
};
int main() {
Sach s1("Nha gia kim", "Paulo Coelho");
Sach s2("De men phieu luu ky", "To Hoai");
Sach s3("Hoang tu be", "Antoine de Saint-Exupery");
ThuVien tv;
tv.them(s1);
tv.them(s2);
tv.them(s3);
tv.hienTatCa();
return 0;
}
Output:
Da them sach: "Nha gia kim"
Da them sach: "De men phieu luu ky"
Da them sach: "Hoang tu be"
--- Cac sach trong thu vien ---
- "Nha gia kim" by Paulo Coelho
- "De men phieu luu ky" by To Hoai
- "Hoang tu be" by Antoine de Saint-Exupery
------------------------------
Bài tập 3: Áp dụng Kế thừa - Hệ thống Hình học cơ bản
Yêu cầu:
- Thiết kế một lớp cơ sở (base class) có tên là
Hinh
. Lớp này có thể có các thuộc tính chung nhưmauSac
(string) và một phương thức hiển thị màu sắc. - Thiết kế hai lớp kế thừa (derived classes) là
HinhTron
vàHinhChuNhat
, kế thừa từ lớpHinh
. - Lớp
HinhTron
cần có thêm thuộc tínhbanKinh
(double) và phương thức tính diện tích riêng. - Lớp
HinhChuNhat
cần có thêm thuộc tínhchieuDai
vàchieuRong
(double) và phương thức tính diện tích riêng. - Minh họa việc tạo đối tượng của các lớp kế thừa và truy cập các thuộc tính, phương thức từ cả lớp cơ sở và lớp kế thừa.
Giải thích:
Bài tập này giúp bạn hiểu và áp dụng nguyên tắc kế thừa (inheritance). Các lớp con (HinhTron
, HinhChuNhat
) kế thừa các đặc điểm chung (mauSac
, hienThiMau
) từ lớp cha (Hinh
), đồng thời bổ sung thêm các đặc điểm riêng của chúng (thuộc tính kích thước, phương thức tính diện tích). Kế thừa giúp tái sử dụng code và tạo ra cấu trúc phân cấp trong chương trình.
Code minh họa:
#include <iostream>
#include <string>
#include <cmath>
#include <iomanip>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
class Hinh {
protected:
string mau;
public:
Hinh(string m) : mau(m) {
cout << "Hinh: Tao hinh mau " << mau << endl;
}
void hienMau() const {
cout << "Hinh nay co mau: " << mau << endl;
}
string getMau() const {
return mau;
}
virtual ~Hinh() {
cout << "Hinh: Huy" << endl;
}
};
class HinhTron : public Hinh {
private:
double r;
public:
HinhTron(string m, double bk) : Hinh(m), r(bk) {
cout << "HinhTron: Ban kinh " << r << endl;
}
double tinhDT() const {
return M_PI * r * r;
}
~HinhTron() override {
cout << "HinhTron: Huy" << endl;
}
};
class HinhChuNhat : public Hinh {
private:
double cd;
double cr;
public:
HinhChuNhat(string m, double cDai, double cRong) : Hinh(m), cd(cDai), cr(cRong) {
cout << "HinhChuNhat: Dai " << cd << ", Rong " << cr << endl;
}
double tinhDT() const {
return cd * cr;
}
~HinhChuNhat() override {
cout << "HinhChuNhat: Huy" << endl;
}
};
int main() {
cout << fixed << setprecision(2);
HinhTron ht("Do", 5.0);
HinhChuNhat hcn("Xanh Duong", 4.0, 6.0);
cout << endl;
ht.hienMau();
hcn.hienMau();
cout << endl;
cout << "Dien tich Hinh Tron (" << ht.getMau() << "): " << ht.tinhDT() << endl;
cout << "Dien tich Hinh Chu Nhat (" << hcn.getMau() << "): " << hcn.tinhDT() << endl;
cout << endl;
cout << "Ket thuc main..." << endl;
return 0;
}
Output:
Hinh: Tao hinh mau Do
HinhTron: Ban kinh 5.00
Hinh: Tao hinh mau Xanh Duong
HinhChuNhat: Dai 4.00, Rong 6.00
Hinh nay co mau: Do
Hinh nay co mau: Xanh Duong
Dien tich Hinh Tron (Do): 78.54
Dien tich Hinh Chu Nhat (Xanh Duong): 24.00
Ket thuc main...
HinhChuNhat: Huy
Hinh: Huy
HinhTron: Huy
Hinh: Huy
Bài tập ví dụ: C++ Bài 24.B2: Quản lý doanh thu bán hàng (OOP)
Quản lý doanh thu bán hàng (OOP)
Đề bài
Công ty FullHouse Dev muốn quản lý doanh thu bán hàng của các nhân viên. Quy tắc đánh giá như sau:
- Doanh thu = Số lượng sản phẩm bán × Giá mỗi sản phẩm
Hãy nhập thông tin doanh thu của các nhân viên và tìm ra nhân viên có doanh thu cao nhất.
Input Format
- Dòng đầu ghi số nhân viên (không quá 100 nhân viên)
- Mỗi nhân viên ghi trên 4 dòng:
- Tên nhân viên
- Số lượng sản phẩm bán
- Giá mỗi sản phẩm
- Mã nhân viên
Output Format
Ghi ra thông tin của nhân viên có doanh thu cao nhất gồm các thông tin:
- Mã nhân viên
- Tên nhân viên
- Số lượng sản phẩm bán
- Giá mỗi sản phẩm
- Doanh thu
Ví dụ
Dữ liệu vào:
3
Nguyen Van A
50
200000
NV001
Tran Thi B
70
150000
NV002
Le Van C
30
100000
NV003
Dữ liệu ra:
NV002 Tran Thi B 70 150000 10500000
Giải thích ví dụ mẫu:
- Đầu vào: Nguyễn Văn A 50 200000 NV001
- Đầu ra: NV002 Trần Thị B 70 150000 10500000
Dòng này hiển thị thông tin chi tiết về nhân viên NV002, bao gồm mã nhân viên, tên, số lượng sản phẩm bán, giá mỗi sản phẩm và doanh thu. Đây là nhân viên có doanh thu cao nhất.
Cách tính doanh thu cho Trần Thị B: Doanh thu = 70 × 150000 = 10500000 Tuyệt vời! Đây là hướng dẫn chi tiết để giải bài tập này bằng C++ sử dụng lập trình hướng đối tượng (OOP), tập trung vào các bước và ý tưởng cốt lõi mà không cung cấp code hoàn chỉnh:
Bước 1: Xác định đối tượng (Object)
Bài toán quản lý doanh thu cho các nhân viên. Rõ ràng, đối tượng trung tâm ở đây chính là "Nhân viên". Chúng ta cần tạo một lớp (class) để biểu diễn một nhân viên bán hàng.
Bước 2: Thiết kế lớp (Class) Employee
Lớp Employee
sẽ chứa các thuộc tính (attributes) cần thiết để lưu trữ thông tin của một nhân viên và các phương thức (methods) để thực hiện các hành động liên quan.
Thuộc tính (Private Members): Để đảm bảo tính đóng gói (encapsulation), các dữ liệu của nhân viên nên được khai báo là
private
.- Tên nhân viên: Kiểu dữ liệu
string
. - Số lượng sản phẩm bán: Kiểu dữ liệu số nguyên (ví dụ
int
). - Giá mỗi sản phẩm: Kiểu dữ liệu số nguyên (ví dụ
int
). - Mã nhân viên: Kiểu dữ liệu
string
.
- Tên nhân viên: Kiểu dữ liệu
Phương thức (Public Members): Cần có các phương thức để tương tác với đối tượng
Employee
.- Constructor: Một phương thức khởi tạo để tạo đối tượng
Employee
từ các thông tin đầu vào. Có thể tạo một constructor nhận tất cả các thông tin (tên, số lượng, giá, mã) làm tham số. - Phương thức tính doanh thu: Một phương thức để tính toán doanh thu dựa trên số lượng và giá. Phương thức này nên trả về kết quả. Kiểu dữ liệu trả về cho doanh thu nên là
long long
để tránh tràn số, vì số lượng và giá có thể lớn khiến tích vượt quá giới hạn củaint
. Phương thức này không làm thay đổi trạng thái của đối tượng, nên đánh dấu làconst
. - Phương thức lấy thông tin (Getters): Cần các phương thức
public
để truy cập các thuộc tínhprivate
khi cần in kết quả (ví dụ:getId()
,getName()
,getQuantity()
,getPrice()
,getRevenue()
). Phương thứcgetRevenue()
có thể gọi lại phương thức tính doanh thu bên trong. Đánh dấu các getter làconst
.
- Constructor: Một phương thức khởi tạo để tạo đối tượng
Bước 3: Đọc dữ liệu và lưu trữ
Trong hàm main()
, bạn sẽ thực hiện việc đọc dữ liệu và tạo các đối tượng Employee
.
- Đọc số lượng nhân viên
n
. - Sử dụng một container để lưu trữ các đối tượng
Employee
.vector<Employee>
là lựa chọn phù hợp và linh hoạt. - Lặp lại
n
lần để đọc thông tin cho từng nhân viên:- Đọc tên (
getline
vì tên có thể chứa khoảng trắng). - Đọc số lượng (
cin >>
). - Đọc giá (
cin >>
). - Quan trọng: Sau khi đọc số nguyên bằng
cin >>
, còn lại ký tự newline trong bộ đệm. Cần xử lý nó trước khi gọigetline
tiếp theo (ví dụ:cin.ignore(numeric_limits<streamsize>::max(), '\n');
hoặc đơn giản hơn làcin.ignore();
nếu chỉ cần bỏ qua 1 ký tự newline). - Đọc mã nhân viên (
getline
). - Tạo một đối tượng
Employee
mới sử dụng constructor với dữ liệu vừa đọc. - Thêm đối tượng này vào
vector
.
- Đọc tên (
Bước 4: Tìm nhân viên có doanh thu cao nhất
Sau khi đã có một vector
chứa tất cả các đối tượng Employee
:
- Khởi tạo biến lưu trữ doanh thu cao nhất tìm được (
max_revenue
, kiểulong long
) và chỉ số (hoặc con trỏ/iterator) của nhân viên tương ứng (max_index
). - Lặp qua
vector
:- Đối với mỗi nhân viên trong vector, gọi phương thức tính doanh thu của họ.
- So sánh doanh thu hiện tại với
max_revenue
. - Nếu doanh thu hiện tại lớn hơn
max_revenue
, cập nhậtmax_revenue
và lưu lại chỉ số (hoặc thông tin khác) của nhân viên này. Có thể bắt đầu với nhân viên đầu tiên làm giả định ban đầu chomax_revenue
vàmax_index
.
Bước 5: In kết quả
Sau khi vòng lặp kết thúc, bạn đã xác định được nhân viên có doanh thu cao nhất (thông qua max_index
).
- Truy cập đối tượng
Employee
tạimax_index
trongvector
. - Sử dụng các phương thức getter của đối tượng này để lấy ra Mã nhân viên, Tên nhân viên, Số lượng sản phẩm bán, Giá mỗi sản phẩm và Doanh thu.
- In các thông tin này ra màn hình theo đúng định dạng yêu cầu, cách nhau bởi dấu cách.
Gợi ý về việc sử dụng std
:
- Sử dụng
cin
,cout
cho nhập/xuất cơ bản. - Sử dụng
string
cho tên và mã. - Sử dụng
vector
để lưu trữ danh sách nhân viên. - Sử dụng
getline
để đọc chuỗi có khoảng trắng. - Sử dụng
cin.ignore()
để xử lý ký tự newline sau khi đọc số. - Sử dụng
long long
cho kiểu dữ liệu doanh thu. - Sử dụng
const
cho các phương thức getter và phương thức tính doanh thu vì chúng không làm thay đổi trạng thái của đối tượng.
#include <iostream>
#include <string>
#include <vector>
#include <limits> // For numeric_limits
#include <iomanip> // For output formatting (though not strictly needed by example)
class NhanVien {
private:
string ma;
string ten;
int sl;
int gia;
long long dt;
public:
NhanVien(string m, string t, int s, int g) : ma(m), ten(t), sl(s), gia(g) {
dt = (long long)sl * gia;
}
long long getDT() const { return dt; }
string getMa() const { return ma; }
string getTen() const { return ten; }
int getSL() const { return sl; }
int getGia() const { return gia; }
};
int main() {
int n;
cin >> n;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
vector<NhanVien> ds;
long long max_dt = -1;
int max_idx = -1;
for (int i = 0; i < n; ++i) {
string ten_nv;
getline(cin, ten_nv);
int sl_sp;
cin >> sl_sp;
int gia_sp;
cin >> gia_sp;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
string ma_nv;
getline(cin, ma_nv);
NhanVien nv(ma_nv, ten_nv, sl_sp, gia_sp);
ds.push_back(nv);
if (nv.getDT() > max_dt) {
max_dt = nv.getDT();
max_idx = i;
}
}
if (max_idx != -1) {
NhanVien nv_max = ds[max_idx];
cout << nv_max.getMa() << " " << nv_max.getTen() << " "
<< nv_max.getSL() << " " << nv_max.getGia() << " "
<< nv_max.getDT() << endl;
}
return 0;
}
Output (with given input):
NV002 Tran Thi B 70 150000 10500000
Comments