Skip to content

Chương 8

Giải trọn một đề thi thật trong 60 phút

Bảy chương trước dạy từng mảnh. Chương này ghép lại, dưới đúng điều kiện phòng thi. Đề dùng ở đây là đề thi thật của học kỳ 2 năm học 2024–2025, không sửa một chữ.

Cách dùng chương này

Đừng đọc hết rồi mới làm. Đọc mục 8.1, đóng sách, bấm giờ 60 phút, tự làm. Xong rồi mới mở phần còn lại để đối chiếu.

Làm lần đầu mà không xong là chuyện bình thường — trung bình lớp của đề này là 4.8. Điều quan trọng là bạn biết mình hụt ở đâu trước ngày thi, chứ không phải sau.

8.1 Đề bài

Mục tiêu 60 phút60:00Chưa bắt đầu

Năm chặng: đọc đề và vẽ UML → dựng khung → cài đặt → chạy và so từng dòng → nộp

cpp
DE 1 - HE THONG PHUONG TIEN GIAO THONG             Thoi gian: 60 phut

1. Lop truu tuong Vehicle
   - Thuoc tinh: string id, string brand, int year
   - Constructor day du
   - virtual void displayInfo() const = 0   (thuan ao)
   - Virtual destructor
2. Lop LandVehicle (truu tuong) ke thua Vehicle: them int wheels
3. Lop AirVehicle  (truu tuong) ke thua Vehicle: them int maxAltitude
4. Lop Car       ke thua LandVehicle: them int seats, string fuelType
5. Lop Motorbike ke thua LandVehicle: them bool hasGear
6. Lop Helicopter ke thua AirVehicle: them int rotors

Trong main():
   - Tao vector chua Vehicle*
   - Them 1 Car, 1 Motorbike, 1 Helicopter
   - Goi displayInfo() bang con tro Vehicle* (da hinh)

Test case:
   Car c("C01", "Toyota", 2020, 4, "Xang", 5);
   Motorbike m("M01", "Honda", 2018, 2, true);
   Helicopter h("H01", "Airbus", 2015, 3000, 4);

Ket qua mong doi:
   [Car] Toyota (C01) - 2020 | Seats: 5 | Fuel: Xang | Wheels: 4
   [Motorbike] Honda (M01) - 2018 | Gear: Co | Wheels: 2
   [Helicopter] Airbus (H01) - 2015 | Altitude: 3000m | Rotors: 4

Thang diem:  Tinh truu tuong 1 | Thiet ke lop truu tuong, ke thua day du 2
             Da hinh qua con tro 1 | Tinh dong goi 1
             Chuong trinh chay dung 3 | Chia file ro rang 2 | UML (bonus) 2

8.2 Phân bổ 60 phút

PhútViệcVì sao
0 – 8Đọc đề, gạch danh từ, vẽ UMLLấy 2 điểm thưởng và có bản kế hoạch
8 – 22Dựng khung: tạo đủ file, viết hết phần khai báo .hLấy chắc 2 điểm chia file trước khi hết giờ
22 – 45Cài đặt từng .cpp, biên dịch sau mỗi lớpPhần dài nhất, nhưng lúc này chỉ còn là gõ
45 – 55Chạy, so output từng dòng với đề3 điểm “chạy đúng”
55 – 60Dọn, nén, đặt tên, nộpMất bài vì nộp sai là mất trắng

Nguyên tắc quan trọng nhất của 60 phút

Lấy điểm chắc trước, điểm khó sau. Chia file 2 điểm và UML 2 điểm là 4 điểm — nhiều hơn cả mục “chạy đúng” — mà không đòi hỏi gì ngoài thao tác. Một bài có đủ file, có UML, chạy được một nửa vẫn hơn hẳn một bài làm dở dang phần logic.

Trung bình lớp là 4.8. Nghĩa là lấy trọn 4 điểm “dễ” cộng một phần “chạy đúng” đã đưa bạn lên trên trung bình.

8.3 Phút 0 – 8: đọc đề và vẽ UML

Đề đã liệt kê sẵn các lớp, nên bước gạch danh từ chỉ mất một phút. Vẽ ngay quan hệ:

Hình 8.1 — Sơ đồ cần vẽ trong 8 phút đầu: ba tầng kế thừa; LandVehicle và AirVehicle vẫn là lớp trừu tượng.Hình 8.1 — Sơ đồ cần vẽ trong 8 phút đầu: ba tầng kế thừa; LandVehicle và AirVehicle vẫn là lớp trừu tượng.
Hình 8.1 — Sơ đồ cần vẽ trong 8 phút đầu: ba tầng kế thừa; LandVehicle và AirVehicle vẫn là lớp trừu tượng.

Ba điều đọc ra được từ sơ đồ, trước khi gõ dòng nào

Ba tầng, không phải hai. Car gọi constructor của LandVehicle, LandVehicle gọi constructor của Vehicle.

Hai lớp giữa vẫn trừu tượng. Đề ghi rõ “(trừu tượng)”. Nghĩa là LandVehicleAirVehicle không cài đặt displayInfo() — chúng chỉ thêm thuộc tính rồi truyền tiếp trách nhiệm xuống.

Sáu lớp = sáu cặp file, trừ hai lớp chỉ cần .h? Không — LandVehicleAirVehicle vẫn có constructor cần cài đặt, nên vẫn đủ cặp .h / .cpp. Tổng cộng 13 file kể cả main.cpp.

Chép sơ đồ này vào đầu main.cpp dưới dạng comment. Xong 2 điểm thưởng, mất 3 phút.

8.4 Phút 8 – 22: dựng khung

Tạo đủ 13 file và viết hết phần khai báo trước, chưa cài đặt gì. Lý do: nếu hết giờ, bạn vẫn có đủ file và đủ thiết kế — đó là 2 điểm chia file cộng 2 điểm thiết kế lớp, lấy được ngay cả khi chương trình chưa chạy.

cpp
#ifndef VEHICLE_H
#define VEHICLE_H

#include <string>

class Vehicle {
protected:                       // protected vi lop con can dung
    std::string id;
    std::string brand;
    int year;

public:
    Vehicle(const std::string& id, const std::string& brand, int year);

    std::string getId() const;   // dong goi: 1 diem
    std::string getBrand() const;
    int getYear() const;

    virtual void displayInfo() const = 0;   // truu tuong: 1 diem
    virtual ~Vehicle();                     // bat buoc khi co ham ao
};

#endif

Tầng giữa chỉ thêm thuộc tính, không cài displayInfo():

cpp
class LandVehicle : public Vehicle {
protected:
    int wheels;

public:
    LandVehicle(const std::string& id, const std::string& brand,
                int year, int wheels);
    int getWheels() const;
};

Tầng lá là nơi duy nhất có override:

cpp
class Car : public LandVehicle {
private:
    int seats;
    std::string fuelType;

public:
    Car(const std::string& id, const std::string& brand, int year,
        int wheels, const std::string& fuelType, int seats);

    void displayInfo() const override;
};

Thứ tự tham số — chỗ mất điểm rất oan

Đề cho test case Car c("C01", "Toyota", 2020, 4, "Xang", 5); — tức là id, brand, year, wheels, fuelType, seats.

Nếu bạn khai báo constructor theo thứ tự ..., seats, fuelType thì dòng test của đề sẽ không biên dịch, hoặc tệ hơn là biên dịch được nhưng gán nhầm. Luôn khai báo constructor đúng thứ tự trong test case của đề, không theo thứ tự bạn thấy hợp lý.

8.5 Phút 22 – 45: cài đặt

Từ đây chỉ còn là gõ theo khung. Chuỗi constructor ba tầng:

text
Vehicle::Vehicle(const string& id, const string& brand, int year)
    : id(id), brand(brand), year(year) {}

LandVehicle::LandVehicle(const string& id, const string& brand,
                         int year, int wheels)
    : Vehicle(id, brand, year), wheels(wheels) {}

Car::Car(const string& id, const string& brand, int year,
         int wheels, const string& fuelType, int seats)
    : LandVehicle(id, brand, year, wheels), seats(seats), fuelType(fuelType) {}

Và phần in — chép định dạng từ đề, từng dấu cách:

cpp
void Car::displayInfo() const {
    cout << "[Car] " << brand << " (" << id << ") - " << year
         << " | Seats: " << seats
         << " | Fuel: " << fuelType
         << " | Wheels: " << wheels << endl;
}

main.cpp đúng như đề yêu cầu:

cpp
vector<Vehicle*> ds;
ds.push_back(new Car("C01", "Toyota", 2020, 4, "Xang", 5));
ds.push_back(new Motorbike("M01", "Honda", 2018, 2, true));
ds.push_back(new Helicopter("H01", "Airbus", 2015, 3000, 4));

for (Vehicle* v : ds)  v->displayInfo();    // da hinh: 1 diem
for (Vehicle* v : ds)  delete v;            // nho tra bo nho

8.6 Phút 45 – 55: chạy và so từng dòng

sh
g++ -std=c++17 -Wall *.cpp -o main.exe
main.exe

Kết quả phải khớp tuyệt đối với khối in trên đề:

text
[Car] Toyota (C01) - 2020 | Seats: 5 | Fuel: Xang | Wheels: 4
[Motorbike] Honda (M01) - 2018 | Gear: Co | Wheels: 2
[Helicopter] Airbus (H01) - 2015 | Altitude: 3000m | Rotors: 4

So output là so từng ký tự

Đây là chỗ mất điểm nhiều nhất mà sinh viên không ngờ tới. Các lỗi thật đã gặp:

"Toyota(C01)" thiếu dấu cách trước ngoặc — đề in "Toyota (C01)".

"2020| Seats" thiếu dấu cách trước gạch đứng — đề in "2020 | Seats".

"Fuel Type:" đề chỉ in "Fuel:".

Cách chắc ăn: mở đề ra, đặt cạnh màn hình, đọc song song từng dòng. Hoặc chép khối kết quả của đề vào comment trong main.cpp ngay từ phút thứ 8.

8.7 Phút 55 – 60: nộp

  1. Xoá main.exe, xoá thư mục .vscode nếu có.
  2. Mở cửa sổ dòng lệnh mới, vào thư mục bài làm, chạy lại lệnh g++ một lần nữa để chắc chắn.
  3. Nén thư mục thành <MSSV>_<Ho ten khong dau>.zip.
  4. Chép vào C:\OOP đúng như đề ghi. Kiểm tra lại là file đã thật sự nằm ở đó.

8.8 Tự chấm

Chấm bài mình vừa làm bằng đúng thang điểm của đề. Trung thực, vì người duy nhất bị thiệt khi chấm rộng tay là chính bạn:

MụcCách tự kiểmĐiểm của bạn
Tính trừu tượng 1Vehicle có hàm thuần ảo = 0 và không tạo đối tượng được
Thiết kế lớp, kế thừa đầy đủ 2Đủ 6 lớp, đúng 3 tầng, hai lớp giữa vẫn trừu tượng
Đa hình qua con trỏ 1vector<Vehicle*> và gọi v->displayInfo()
Tính đóng gói 1protected/private + có getter
Chạy đúng, test case hợp lý 3Output khớp từng ký tự với đề
Chia file rõ ràng 213 file, đúng tên, có header guard, không include .cpp
UML (bonus) +2Có sơ đồ, dù chỉ là comment trong main.cpp

Tổng 0/10

8.9 Mười chỗ mất điểm dù code gần đúng

  1. Quên ; sau dấu } đóng lớp.
  2. Quên virtual ~Vehicle() — mất điểm thiết kế và rò rỉ bộ nhớ.
  3. Cài displayInfo()LandVehicle trong khi đề ghi lớp đó trừu tượng.
  4. Constructor sai thứ tự tham số so với test case của đề.
  5. Dùng vector<Vehicle> thay vì vector<Vehicle*> — object slicing, mất luôn điểm đa hình.
  6. Thiếu một dấu cách trong chuỗi in.
  7. Gộp nhiều lớp vào một file .h — mất điểm chia file.
  8. #include "Car.cpp" thay vì đưa file vào lệnh biên dịch.
  9. Quên override, gõ thiếu const nên ghi đè hụt mà không biết.
  10. Không vẽ UML — bỏ trắng 2 điểm thưởng.

Lời giải đầy đủ

Bản giải hoàn chỉnh của đề này nằm ở TH/2026/giaotrinh/vi_du/de_thi_vehicle/, 13 file, biên dịch sạch với -Wall -Wextra và cho ra đúng ba dòng output ở mục 8.6.

Chỉ mở nó sau khi đã tự làm hết 60 phút. Đọc lời giải trước khi tự vật lộn là cách nhanh nhất để tưởng mình biết làm — và mục 0.1 đã cho thấy cảm giác đó tốn kém thế nào.

Tự kiểm tra — đề thứ hai, tự lực hoàn toàn

Mục tiêu 60 phút60:00Chưa bắt đầu

Năm chặng: đọc đề và vẽ UML → dựng khung → cài đặt → chạy và so từng dòng → nộp

60 phút, bấm giờ, không mở sách.

text
QUAN LY KHOA HOC TRUC TUYEN                       (de thi HK1 2025-2026)

Cau 1 (6 diem)
  1. Lop truu tuong Course:
     - protected string title
     - Ham thuan ao string getType()
  2. Lop ke thua:
     - OnlineCourse : them int videoCount
     - OfflineCourse: them string location
  3. Trong main(): tao 1 khoa online, 1 khoa offline, goi getType()

  Ket qua mong doi:
     [OnlineCourse] Lap trinh C++, So video: 25
     Loai khoa hoc: Online
     [OfflineCourse] OOP Nang cao, Dia diem: Phong B101
     Loai khoa hoc: Offline

Cau 2 (4 diem)
  1. Lop Enrollment: private int fee, getter getFee()
     Constructor: neu fee <= 0 -> throw invalid_argument("Hoc phi khong hop le!")
  2. Lop ScholarshipEnrollment ke thua Enrollment: override getFee() (giam 50%)
  3. Trong main(): dung Enrollment*, tao 2 dang ky hop le, 1 dang ky loi, bat ngoai le

  Ket qua mong doi:
     Dang ky khoa hoc, hoc phi: 2000000
     Dang ky hoc bong, hoc phi: 1000000
     Loi: Hoc phi khong hop le!

Thang diem: Thiet ke dung lop 2 | Ham ao va override 2 | Ngoai le 1
            Chay dung 3 | Chia file 2 | UML/comment (bonus) 2

Đề này gộp chương 5, 6 và 7. Làm xong hãy tự chấm bằng bảng ở mục 8.8, và ghi lại ba chỗ mất điểm lớn nhất của mình. Ba chỗ đó chính là những chương bạn cần đọc lại.

Đọc xong và tự làm hết phần “Tự kiểm tra” rồi hãy đánh dấu.

© 2026 Ngan V.T. Nguyen · Nội dung theo giấy phép CC BY-NC-SA 4.0 · Code ví dụ theo giấy phép MIT · Ảnh của bên thứ ba giữ giấy phép riêng, ghi ở Phụ lục E

Nội dung theo giấy phép CC BY-NC-SA 4.0 · Code ví dụ theo giấy phép MIT · Ảnh của bên thứ ba giữ giấy phép riêng, ghi ở Phụ lục E