Giao diện
🎯 Tại sao OOP?
OOP không phải là "cách viết code mới" — nó là cách tư duy mới về phần mềm. Thay vì hỏi "làm gì?", ta hỏi "ai làm gì?"
Vấn đề với Procedural Programming
C-style: Data và Functions tách rời
cpp
// C-style: Data riêng, functions riêng
struct BankAccount {
int id;
double balance;
char ownerName[100];
};
void deposit(BankAccount* acc, double amount) {
acc->balance += amount; // Ai cũng có thể gọi!
}
void withdraw(BankAccount* acc, double amount) {
acc->balance -= amount; // Không validate!
}
int main() {
BankAccount acc = {1, 1000.0, "Alice"};
// ❌ VẤN ĐỀ 1: Ai cũng có thể truy cập trực tiếp
acc.balance = -999999; // Số dư âm? No protection!
// ❌ VẤN ĐỀ 2: Dễ quên gọi function đúng
acc.balance += 500; // Bypass deposit(), không log!
return 0;
}Các vấn đề:
| Problem | Description |
|---|---|
| No encapsulation | Ai cũng access được data |
| No invariants | Không đảm bảo rules (balance >= 0) |
| Scattered logic | Code liên quan nằm rải rác |
| Hard to maintain | Thay đổi struct → sửa mọi nơi |
OOP Solution: Gói data + behavior
cpp
#include <iostream>
#include <string>
#include <stdexcept>
class BankAccount {
private: // 🔒 Chỉ class mới access được
int id_;
double balance_;
std::string ownerName_;
public:
// Constructor
BankAccount(int id, const std::string& owner, double initialBalance)
: id_(id), ownerName_(owner), balance_(initialBalance) {
if (initialBalance < 0) {
throw std::invalid_argument("Initial balance cannot be negative");
}
}
// Getter (read-only access)
double getBalance() const {
return balance_;
}
// Deposit với validation
void deposit(double amount) {
if (amount <= 0) {
throw std::invalid_argument("Deposit amount must be positive");
}
balance_ += amount;
std::cout << "Deposited: " << amount << ", New balance: " << balance_ << std::endl;
}
// Withdraw với validation
bool withdraw(double amount) {
if (amount <= 0 || amount > balance_) {
std::cout << "Withdrawal failed!" << std::endl;
return false;
}
balance_ -= amount;
std::cout << "Withdrew: " << amount << ", New balance: " << balance_ << std::endl;
return true;
}
};
int main() {
BankAccount acc(1, "Alice", 1000.0);
// ✅ Chỉ có thể tương tác qua methods
acc.deposit(500); // OK
acc.withdraw(200); // OK
acc.withdraw(9999); // FAIL — validation!
// ❌ Không thể access trực tiếp
// acc.balance_ = -999; // Compiler error: private!
std::cout << "Final balance: " << acc.getBalance() << std::endl;
return 0;
}Mapping Real World → Classes
OOP hoạt động tốt vì nó mô phỏng cách ta nghĩ về thế giới:
┌─────────────────────────────────────────────────────────────────┐
│ REAL WORLD → C++ CLASSES │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 🚗 XE HƠI class Car { │
│ ───────── private: │
│ Thuộc tính: std::string brand_; │
│ - Hãng int speed_; │
│ - Tốc độ double fuel_; │
│ - Nhiên liệu public: │
│ Hành vi: void accelerate(); │
│ - Tăng tốc void brake(); │
│ - Phanh void refuel(double); │
│ - Đổ xăng }; │
│ │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 👤 NGƯỜI DÙNG class User { │
│ ───────────── private: │
│ Thuộc tính: std::string username_; │
│ - Username std::string passwordHash_; │
│ - Password (hashed) int accessLevel_; │
│ - Quyền truy cập public: │
│ Hành vi: bool login(pwd); │
│ - Đăng nhập void logout(); │
│ - Đăng xuất bool hasPermission(action); │
│ - Kiểm tra quyền }; │
│ │
└─────────────────────────────────────────────────────────────────┘4 Trụ cột của OOP
1. Encapsulation (Đóng gói) ✅ Học trong module này
Gói data + methods vào một đơn vị, ẩn implementation details.
cpp
class Secret {
private:
std::string password_; // Ẩn bên trong
public:
bool verify(const std::string& input) { // Chỉ expose interface
return input == password_;
}
};2. Abstraction (Trừu tượng hóa) ✅ Học trong module này
Chỉ show "what" (interface), ẩn "how" (implementation).
cpp
class EmailSender {
public:
void send(const std::string& to, const std::string& msg);
// User không cần biết SMTP protocol bên trong!
};3. Inheritance (Kế thừa) 🔜 Module tiếp theo
Tạo class mới dựa trên class đã có.
cpp
class Animal { ... };
class Dog : public Animal { ... }; // Dog "is-a" Animal4. Polymorphism (Đa hình) 🔜 Module tiếp theo
Một interface, nhiều implementations.
cpp
Animal* pet = new Dog();
pet->speak(); // "Woof!" — runtime polymorphismKhi nào KHÔNG nên dùng OOP?
OOP không phải silver bullet. Tránh over-engineering:
| Situation | Recommendation |
|---|---|
| Small scripts | Procedural đủ tốt |
| Pure data containers | Dùng struct (all public) |
| Performance-critical inner loops | Data-oriented design |
| Simple utilities | Free functions |
📌 HPN Standard
Dùng OOP khi cần:
- State management (objects có state phức tạp)
- Encapsulation (bảo vệ invariants)
- Reusability (nhiều nơi dùng cùng pattern)
- Modeling (domain problems với entities rõ ràng)
📚 Tổng kết
| Concept | Key Takeaway |
|---|---|
| Procedural | Data + Functions tách rời, khó maintain |
| OOP | Data + Behavior = Object, dễ reason about |
| Encapsulation | Ẩn data, chỉ expose interface |
| Abstraction | Ẩn complexity, show essentials |
| Real-world mapping | Classes phản ánh entities thực tế |
➡️ Tiếp theo
Tiếp theo: Class Anatomy — Cấu trúc chi tiết của một class.