Giao diện
🏗️ 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 runsMember 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
| Rule | Description |
|---|---|
Tên = ~ClassName() | Không có return type |
| Không có parameters | Không thể overload |
| Tự động gọi | Khi object ra khỏi scope hoặc delete |
| Virtual cho inheritance | virtual ~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
| Component | Purpose |
|---|---|
| Member variables | Store object state |
| Member functions | Define object behavior |
| Constructor | Initialize object |
| Destructor | Cleanup when destroyed |
const methods | Read-only access |
explicit | Prevent implicit conversion |
| RAII | Resource management pattern |
➡️ Tiếp theo
Tiếp theo: Access Modifiers — public, private, protected và Data Hiding.