Skip to content

🏗️ Class Anatomy — Cấu trúc Class

Một class là bản thiết kế (blueprint) cho objects. Hiểu các thành phần của class là nền tảng để viết OOP code chất lượng.

Cấu trúc cơ bản của Class

cpp
#include <iostream>
#include <string>

class Person {
private:                    // 🔒 Private section
    std::string name_;      // Member variable
    int age_;

public:                     // 🔓 Public section
    // Constructor
    Person(const std::string& name, int age)
        : name_(name), age_(age) {}
    
    // Member function (method)
    void introduce() const {
        std::cout << "Hi, I'm " << name_ << ", " << age_ << " years old." << std::endl;
    }
    
    // Getter
    std::string getName() const { return name_; }
    int getAge() const { return age_; }
    
    // Setter
    void setAge(int age) { age_ = age; }
    
    // Destructor
    ~Person() {
        std::cout << name_ << " is being destroyed." << std::endl;
    }
};

int main() {
    Person alice("Alice", 25);
    alice.introduce();
    
    return 0;
}  // alice destroyed here → destructor runs

Member Variables (Data Members)

Naming Convention

cpp
class MyClass {
private:
    // HPN Standard: Suffix underscore cho member variables
    int count_;           // ✅ Rõ ràng đây là member
    std::string name_;    // ✅ 
    double balance_;      // ✅
    
    // Các conventions khác (less common):
    // int m_count;       // Hungarian notation
    // int _count;        // Leading underscore (avoid: reserved in some cases)
};

📌 Tại sao suffix underscore?

  • Phân biệt member vs local/parameter
  • Tránh shadowing trong constructor
  • Google C++ Style Guide recommend convention này

Default Member Initializers (C++11)

cpp
class Config {
private:
    int maxConnections_ = 100;      // Default value
    bool debugMode_ = false;
    std::string logPath_ = "/var/log/app.log";
    
public:
    Config() = default;  // Uses defaults
    
    Config(int maxConn)  // Override một số
        : maxConnections_(maxConn) {}  // debugMode_ và logPath_ vẫn dùng default
};

Member Functions (Methods)

Regular Methods

cpp
class Calculator {
private:
    double result_ = 0;
    
public:
    void add(double x) {
        result_ += x;
    }
    
    void multiply(double x) {
        result_ *= x;
    }
    
    double getResult() const {  // const method — không modify state
        return result_;
    }
    
    void reset() {
        result_ = 0;
    }
};

const Methods — Cam kết không thay đổi object

cpp
class BankAccount {
private:
    double balance_;
    
public:
    // ✅ const method — có thể gọi trên const object
    double getBalance() const {
        return balance_;
    }
    
    // ✅ const method — read-only operations
    void printStatement() const {
        std::cout << "Balance: " << balance_ << std::endl;
    }
    
    // ❌ Non-const — modifies state
    void deposit(double amount) {
        balance_ += amount;
    }
};

int main() {
    const BankAccount acc;  // const object
    
    acc.getBalance();     // ✅ OK — const method
    acc.printStatement(); // ✅ OK — const method
    // acc.deposit(100);  // ❌ Error: deposit is non-const
}

Constructors — Khởi tạo Object

Default Constructor

cpp
class Point {
private:
    int x_, y_;
    
public:
    // Default constructor — không tham số
    Point() : x_(0), y_(0) {}
    
    // Hoặc với C++11:
    // Point() = default;  // Chỉ works nếu có default member init
};

int main() {
    Point p1;        // Gọi default constructor
    Point p2{};      // Uniform initialization, same effect
    Point* p3 = new Point();  // Heap allocation
    delete p3;
}

Parameterized Constructor

cpp
class Rectangle {
private:
    double width_, height_;
    
public:
    // Parameterized constructor
    Rectangle(double width, double height)
        : width_(width), height_(height) {}
    
    double area() const {
        return width_ * height_;
    }
};

int main() {
    Rectangle r1(10.0, 5.0);   // Direct initialization
    Rectangle r2{10.0, 5.0};   // Uniform initialization (C++11)
    
    std::cout << "Area: " << r1.area() << std::endl;
}

Constructor Overloading

cpp
class Date {
private:
    int day_, month_, year_;
    
public:
    // Default — today (giả sử)
    Date() : day_(1), month_(1), year_(2024) {}
    
    // Full date
    Date(int day, int month, int year)
        : day_(day), month_(month), year_(year) {}
    
    // Year only — default to Jan 1
    Date(int year)
        : day_(1), month_(1), year_(year) {}
    
    void print() const {
        std::cout << day_ << "/" << month_ << "/" << year_ << std::endl;
    }
};

int main() {
    Date d1;              // 1/1/2024
    Date d2(15, 3, 2025); // 15/3/2025
    Date d3(2030);        // 1/1/2030
}

explicit Keyword — Ngăn implicit conversion

cpp
class Meter {
private:
    double value_;
    
public:
    // ❌ Có thể gây bug:
    // Meter(double v) : value_(v) {}
    
    // ✅ An toàn hơn:
    explicit Meter(double v) : value_(v) {}
    
    double getValue() const { return value_; }
};

void printLength(Meter m) {
    std::cout << m.getValue() << " meters" << std::endl;
}

int main() {
    Meter m1(5.0);        // ✅ OK — explicit call
    // Meter m2 = 5.0;    // ❌ Error với explicit
    printLength(Meter(10.0));  // ✅ OK — explicit
    // printLength(10.0);       // ❌ Error với explicit
}

⚠️ Best Practice

Luôn dùng explicit cho constructor 1 tham số để tránh implicit conversions bất ngờ.


Destructors — Dọn dẹp khi Object bị destroy

cpp
#include <iostream>

class FileHandler {
private:
    std::string filename_;
    bool isOpen_;
    
public:
    FileHandler(const std::string& filename)
        : filename_(filename), isOpen_(true) {
        std::cout << "Opening file: " << filename_ << std::endl;
    }
    
    // Destructor — tên class với ~ prefix
    ~FileHandler() {
        if (isOpen_) {
            std::cout << "Closing file: " << filename_ << std::endl;
            isOpen_ = false;
        }
    }
    
    void write(const std::string& data) {
        if (isOpen_) {
            std::cout << "Writing: " << data << std::endl;
        }
    }
};

int main() {
    {
        FileHandler file("data.txt");
        file.write("Hello, World!");
    }  // file goes out of scope → destructor called automatically
    
    std::cout << "File has been closed." << std::endl;
    
    return 0;
}

Output:

Opening file: data.txt
Writing: Hello, World!
Closing file: data.txt
File has been closed.

Destructor Rules

RuleDescription
Tên = ~ClassName()Không có return type
Không có parametersKhông thể overload
Tự động gọiKhi object ra khỏi scope hoặc delete
Virtual cho inheritancevirtual ~Base() nếu có derived classes

RAII Pattern — Resource Acquisition Is Initialization

cpp
class DatabaseConnection {
private:
    std::string connectionString_;
    bool connected_;
    
public:
    // Constructor: Acquire resource
    DatabaseConnection(const std::string& connStr)
        : connectionString_(connStr), connected_(true) {
        std::cout << "Connected to: " << connStr << std::endl;
    }
    
    // Destructor: Release resource
    ~DatabaseConnection() {
        if (connected_) {
            std::cout << "Disconnecting from: " << connectionString_ << std::endl;
            connected_ = false;
        }
    }
    
    void query(const std::string& sql) {
        if (connected_) {
            std::cout << "Executing: " << sql << std::endl;
        }
    }
};

int main() {
    {
        DatabaseConnection db("mysql://localhost:3306");
        db.query("SELECT * FROM users");
        // Không cần gọi close()! Destructor sẽ tự động cleanup
    }
    std::cout << "Database connection automatically closed!" << std::endl;
}
)}}

🎓 Professor Tom's Note

RAII là pattern cốt lõi của C++:

  • Constructor acquires resources (memory, files, locks, connections)
  • Destructor releases resources automatically
  • Đảm bảo no resource leaks kể cả khi exception xảy ra

📚 Tổng kết

ComponentPurpose
Member variablesStore object state
Member functionsDefine object behavior
ConstructorInitialize object
DestructorCleanup when destroyed
const methodsRead-only access
explicitPrevent implicit conversion
RAIIResource management pattern

➡️ Tiếp theo

Tiếp theo: Access Modifiers — public, private, protected và Data Hiding.