Menu
CoddyTech

Struct và lớp

Thuộc phần Lập trình hướng đối tượng trong hành trình C++ của Coddy. Bài học 37 trên 104.

Trong C++, struct và class gần như giống hệt nhau. Cả hai đều có thể có biến thành viên, hàm thành viên, hàm khởi tạo và hỗ trợ tính kế thừa. Điểm khác biệt duy nhất là mức truy cập mặc định.

Trong một class, các thành viên mặc định là private. Trong một struct, các thành viên mặc định là public:

struct Point {
    int x;    // mặc định là public
    int y;    // mặc định là public
};

class Circle {
    double radius;    // mặc định là private
    
public:
    double getRadius() { return radius; }
};

Điều này cũng áp dụng cho tính kế thừa. Theo mặc định, struct kế thừa công khai, còn class kế thừa riêng tư:

struct DerivedStruct : Base {};    // kế thừa công khai
class DerivedClass : Base {};      // kế thừa riêng tư

Ngoài các giá trị mặc định này, không có khác biệt nào về mặt kỹ thuật. Tuy nhiên, quy ước vẫn rất quan trọng.

Hầu hết lập trình viên C++ dùng struct làm vùng chứa dữ liệu đơn giản với các thành viên công khai (như tọa độ hoặc cấu hình), và dùng class khi tính đóng gói và hành vi đóng vai trò quan trọng. Tuân theo quy ước này giúp các lập trình viên khác hiểu rõ hơn ý định trong code của bạn.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống cấu hình đơn giản để minh họa khi nào nên dùng struct thay vì class theo quy ước của C++. Bạn sẽ tạo một struct cho dữ liệu đơn giản cần được truy cập công khai và một class cho dữ liệu cần đóng gói và kiểm soát quyền truy cập.

Bạn sẽ tạo hai tệp để sắp xếp code:

  • Config.h: Định nghĩa một struct và một lớp, đại diện cho các loại dữ liệu cấu hình khác nhau.

    Trước tiên, hãy tạo một struct tên là Dimensions: một vùng chứa dữ liệu đơn giản gồm chiều rộng và chiều cao (cả hai đều có kiểu int). Vì các thành viên của struct mặc định là công khai, bạn có thể truy cập trực tiếp mà không cần hàm getter. Thêm phương thức area() để trả về tích của chiều rộng và chiều cao.

    Tiếp theo, hãy tạo một class tên là AppConfig để quản lý các thiết lập ứng dụng với tính đóng gói phù hợp. Lớp này cần lưu tên ứng dụng (chuỗi) và một đối tượng Dimensions đại diện cho kích thước cửa sổ. Vì các thành viên của lớp mặc định là riêng tư, bạn cần chủ động khai báo giao diện công khai. Hãy cung cấp:

    • Một hàm khởi tạo nhận tên ứng dụng, chiều rộng và chiều cao
    • Một hàm getter getAppName() trả về tên
    • Một hàm getter getWindowSize() trả về Dimensions
    • Một phương thức displayConfig() in ra: "App: <name>, Window: <width>x<height>, Area: <area>"
  • main.cpp: Minh họa sự khác nhau giữa cách dùng struct và lớp. Đọc tên ứng dụng, chiều rộng và chiều cao từ đầu vào (ba dòng riêng biệt), sau đó:
    • Tạo trực tiếp một struct Dimensions với các giá trị chiều rộng và chiều cao, truy cập trực tiếp các thành viên để in ra: "Direct struct access: <width> x <height>"
    • Tạo một đối tượng AppConfig với cả ba giá trị
    • Gọi displayConfig() để hiển thị toàn bộ cấu hình
    • Dùng hàm getter để lấy kích thước cửa sổ và in ra: "Via getter - Area: <area>"

Thử thách này làm nổi bật quy ước: dùng struct khi bạn có dữ liệu đơn giản, minh bạch (chẳng hạn như tọa độ hoặc kích thước), và dùng class khi bạn muốn kiểm soát quyền truy cập và bổ sung hành vi cho dữ liệu.

Chuyển đầu vào chiều rộng và chiều cao từ chuỗi sang số nguyên bằng std::stoi(). Đừng quên các header guard trong tệp header.

Tự làm thử

#include <iostream>
#include <string>
#include "Config.h"

using namespace std;

int main() {
    // Đọc đầu vào
    string appName;
    string widthStr;
    string heightStr;
    
    getline(cin, appName);
    getline(cin, widthStr);
    getline(cin, heightStr);
    
    int width = stoi(widthStr);
    int height = stoi(heightStr);
    
    // TODO: Tạo struct Dimensions với width và height
    // Truy cập trực tiếp các thành viên của nó để in ra: "Direct struct access: <width> x <height>"
    
    // TODO: Tạo đối tượng AppConfig với appName, width và height
    
    // TODO: Gọi displayConfig() trên đối tượng AppConfig
    
    // TODO: Dùng phương thức getter getWindowSize() để lấy kích thước và in ra: "Via getter - Area: <area>"
    
    return 0;
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch C++ online